2

Here is the simple case.

I have a Customer record defined like this:

 public class Customer
   {
      [Key]
      public string Id { get;}
      public UsState UsState { get; set; }
   }

 public class UsState
   {
      [Key]
      public string  StateAbbreviation {get;set;}
      public string  StateName {get;set;}
   }

I already have my UsState's populated with the 50 states, now I want to insert one Customer record that ties to an existing state.

If I say something like:

Customer customer = new Customer() 
             {
                UsState = "CA",
                Id = 1001
             }
dbContext.Customers.add(customer);

I get an error saying state is trying to be inserted again.

How can I get the add to use an existing state and not try and re-insert it. My real problem has lots of nested objects that may exist so I need to solve this in general.

Thanks

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Peter Kellner
  • 14,748
  • 25
  • 102
  • 188

2 Answers2

2

Two ways I know is:

  1. Set EntityState to what is appropriate for your action or

  2. Get the UsState from the database and add it to the customer right before saving, which will give it an EntityState of UnModified or something like that.

to change the EntityState you need to get to the ObjectContext of your DbContext like shown in this thread: Entity Framework Code First - No Detach() method on DbContext

Community
  • 1
  • 1
Joakim
  • 2,217
  • 15
  • 20
  • Hi Joakim, I'm not trying to be dense, but I just don't get from the article how I need to do what I need. I'm inserting from scratch a record where the UsState exists, but the the rest of the record does not. that is, I have dbContext.Customers.add(customer). I don't see how to attach or detach customer. I'm not a EF wizard (obviously). I also could not figure out how to do your #1 suggestions. I tried to do db.UsStates.where(...).firstordefault() and assign that to Customer.UsState but that did not work (same error about duplicate insert) – Peter Kellner Jan 15 '12 at 02:00
  • Actually Joakim, your #1 did work. I was confused because my first record I was testing with actually did not exist in the UsState table. I am interested in #2, that sounds like a more general solution. I'd appreciate if you could help explain that to me. I don't get the post. -Thanks – Peter Kellner Jan 15 '12 at 02:05
  • @PeterKellner what I meant with #2 is that that you use some kind of ID to fetch UsState from the database and just add that entity to the Customer. In #1 we take responsibility and tell EF that it exists even if it might not. – Joakim Jan 15 '12 at 04:18
0

If you think about this in terms of table data, your Customer table should have a column in it that describes the customer's state. You also have a state table that you can use to join together to get the state name.

CREATE TABLE customer (
    id  VARCHAR(10),
    state CHAR(2)
)

CREATE TABLE state (
    stateabbreviation CHAR(2),
    statename VARCHAR(50)
)

The "state" column is a just a string representing the state. So your class should be defined the same way, with and ID and a State, and if you want to include the information for your USState class, defined a property of type UsState with a ForeignKey defined:

public class Customer
{
    [Key]
    public string Id { get;}
    public string State { get; set; }
    [ForeignKey("State")]
    public UsState UsState { get; set; }
}

Then, when you create a new record, set the text of the string, not the UsState object.

Customer customer = new Customer() 
{
    State = "CA",
    Id = 1001
}
dbContext.Customers.add(customer);
scott.korin
  • 2,537
  • 2
  • 23
  • 36
  • In fact, I'm not sure how the UsState = "CA" in the new call isn't causing an error, since UsState is a class, not a string. – scott.korin Jan 15 '12 at 01:22
  • then you should read this: http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx very useful depending on what you do. – Joakim Jan 15 '12 at 01:25
  • Hi Scott, you are right in that it did not work. what I meant is that I had a function call GetUsState("CA") which returned the state object. I'll try what you suggest. It seems odd should have to create a duplicate string for state to get this to work the way I want. – Peter Kellner Jan 15 '12 at 01:25
  • HI Scott, I tried your code but still when I call savechanges I get the foreigh key error. It's not obvious to me how putting a value as State = "CA" will trigger the update to load the proper state into the UsSTate UsState object. I'm 99% sure I followed you example code above correctly. – Peter Kellner Jan 15 '12 at 01:50
  • FYI, anyone else looking here, there is a good article here: http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx on attaching and detaching but it still does not help me with my issue sadly. – Peter Kellner Jan 16 '12 at 02:58