Note that there are some explanatory texts on larger screens.

plurals
  1. POEF 4.1 Code First - duplicate entities in object graph causes exception
    primarykey
    data
    text
    <p>I am getting the following exception when attempting to save my entity:</p> <p><em>"AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges."</em></p> <p>I'm creating a 3 tiered application where the data access layer is using EF Code First, and where the client calls the middle tier using WCF. I am therefore unable able to let the context track the entity state when building up an entity on the client.</p> <p>In some situations I am finding that the same entity is contained twice in the object graph. In this situation it fails when I try and set the entity state of the duplicate.</p> <p>For example, I have the following entities: Customer Country Curreny</p> <ol> <li>From the client I create a new instance of a Customer. I then make a service call to get Country instance and assign it to the Customer. The Country instance has an associated Currency.</li> <li>The user can then associate a Currency with the customer. They may well choose the same Currency that's associated with the Country.</li> <li>I make another service call to get this. Thus at this stage we may have two separate instances of the same currency.</li> </ol> <p>So what I end up with are two instance of the same entity in the object graph.</p> <p>When then saving the entity (in my service) I need to tell EF that both Currency entities are not modified (if I don't do this I get duplicates). Problem is that I get the exception above.</p> <p>On saving if I set the Currency instance on Country instance to null, it resolves the problem, but I feel like the code is becoming increasingly messy (due to this and other WCF related EF workarounds I'm having to put in place).</p> <p>Are there any suggestions on how to resolve this in a nicer way?</p> <p>Many thanks for any help in advance. Here's the code:</p> <pre><code>using System; using System.Collections.Generic; using System.Data.Entity.ModelConfiguration; using System.ComponentModel.DataAnnotations; using System.Data.Entity; using System.Linq; namespace OneToManyWithDefault { public class Customer { public int Id { get; set; } public string Name { get; set; } public Country Country { get; set; } public Currency Currency { get; set; } public byte[] TimeStamp { get; set; } } public class Country { public int Id { get; set; } public string Name { get; set; } public Currency Currency { get; set; } public byte[] TimeStamp { get; set; } } public class Currency { public int Id { get; set; } public string Symbol { get; set; } public byte[] TimeStamp { get; set; } } public class MyContext : DbContext { public DbSet&lt;Customer&gt; Customers { get; set; } public DbSet&lt;Currency&gt; Currency { get; set; } public DbSet&lt;Country&gt; Country { get; set; } public MyContext(string connectionString) : base(connectionString) { Configuration.LazyLoadingEnabled = false; Configuration.ProxyCreationEnabled = false; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new CustomerConfiguration()); modelBuilder.Configurations.Add(new CountryConfiguration()); modelBuilder.Configurations.Add(new CurrencyConfiguration()); base.OnModelCreating(modelBuilder); } } public class CustomerConfiguration : EntityTypeConfiguration&lt;Customer&gt; { public CustomerConfiguration() : base() { HasKey(p =&gt; p.Id); Property(p =&gt; p.Id) .HasColumnName("Id") .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) .IsRequired(); Property(p =&gt; p.TimeStamp) .HasColumnName("TimeStamp") .IsRowVersion(); ToTable("Customers"); } } public class CountryConfiguration : EntityTypeConfiguration&lt;Country&gt; { public CountryConfiguration() : base() { HasKey(p =&gt; p.Id); Property(p =&gt; p.Id) .HasColumnName("Id") .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) .IsRequired(); Property(p =&gt; p.TimeStamp) .HasColumnName("TimeStamp") .IsRowVersion(); ToTable("Countries"); } } public class CurrencyConfiguration : EntityTypeConfiguration&lt;Currency&gt; { public CurrencyConfiguration() : base() { HasKey(p =&gt; p.Id); Property(p =&gt; p.Id) .HasColumnName("Id") .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) .IsRequired(); Property(p =&gt; p.TimeStamp) .HasColumnName("TimeStamp") .IsRowVersion(); ToTable("Currencies"); } } class Program { private const string ConnectionString = @"Server=.\sql2005;Database=DuplicateEntities;integrated security=SSPI;"; static void Main(string[] args) { // Seed the database MyContext context1 = new MyContext(ConnectionString); Currency currency = new Currency(); currency.Symbol = "GBP"; context1.Currency.Add(currency); Currency currency2 = new Currency(); currency2.Symbol = "USD"; context1.Currency.Add(currency2); Country country = new Country(); country.Name = "UK"; country.Currency = currency; context1.Country.Add(country); context1.SaveChanges(); // Now add a new customer Customer customer = new Customer(); customer.Name = "Customer1"; // Assign a country to the customer // Create a new context (to simulate making service calls over WCF) MyContext context2 = new MyContext(ConnectionString); var countries = from c in context2.Country.Include(c =&gt; c.Currency) where c.Name == "UK" select c; customer.Country = countries.First(); // Assign a currency to the customer // Again create a new context (to simulate making service calls over WCF) MyContext context3 = new MyContext(ConnectionString); customer.Currency = context3.Currency.First(e =&gt; e.Symbol == "GBP"); // Again create a new context (to simulate making service calls over WCF) MyContext context4 = new MyContext(ConnectionString); context4.Customers.Add(customer); // Uncommenting the following line prevents the exception raised below //customer.Country.Currency = null; context4.Entry(customer.Country).State = System.Data.EntityState.Unchanged; context4.Entry(customer.Currency).State = System.Data.EntityState.Unchanged; // The following line will result in this exception: // AcceptChanges cannot continue because the object's key values conflict with another // object in the ObjectStateManager. Make sure that the key values are unique before // calling AcceptChanges. context4.Entry(customer.Country.Currency).State = System.Data.EntityState.Unchanged; context4.SaveChanges(); Console.WriteLine("Done."); Console.ReadLine(); } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload