При попытке сохранить мою сущность я получаю следующее исключение:
"AcceptChanges не может продолжить работу, поскольку значения ключа объекта конфликтуют с другим объектом в ObjectStateManager. Убедитесь, что значения ключа уникальныперед вызовом AcceptChanges. "
Я создаю трехуровневое приложение, в котором уровень доступа к данным сначала использует код EF, а клиент вызывает средний уровень с помощью WCF.Поэтому я не могу позволить контексту отслеживать состояние объекта при создании объекта на клиенте.
В некоторых ситуациях я обнаруживаю, что один и тот же объект дважды содержится в графе объектов.В этой ситуации происходит сбой, когда я пытаюсь установить состояние объекта дубликата.
Например, у меня есть следующие объекты: Страна клиента Валюта
- От клиента, которого я создаюновый экземпляр клиента.Затем я звоню в службу поддержки, чтобы получить экземпляр Country и назначить его Заказчику.Экземпляр Country имеет связанную валюту.
- Пользователь может затем связать валюту с клиентом.Они вполне могут выбрать ту же валюту, которая связана со страной.
- Я звоню в другой сервис, чтобы получить это.Таким образом, на этом этапе у нас могут быть два отдельных экземпляра одной и той же валюты.
Итак, в результате я получаю два экземпляра одного и того же объекта в графе объектов.
Когда тогдаСохраняя сущность (в моем сервисе), я должен сказать EF, что обе сущности Валюты не изменены (если я этого не сделаю, я получу дубликаты).Проблема в том, что я получаю исключение выше.
При сохранении, если я устанавливаю экземпляр Currency на экземпляре Country на null, это решает проблему, но я чувствую, что код становится все более запутанным (из-за этого и другихОбходные пути EF, связанные с WCF, которые я должен применить).
Есть ли какие-либо предложения о том, как решить эту проблему лучше?
Большое спасибо за любую помощь заранее.Вот код:
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<Customer> Customers { get; set; }
public DbSet<Currency> Currency { get; set; }
public DbSet<Country> 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<Customer>
{
public CustomerConfiguration()
: base()
{
HasKey(p => p.Id);
Property(p => p.Id)
.HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(p => p.TimeStamp)
.HasColumnName("TimeStamp")
.IsRowVersion();
ToTable("Customers");
}
}
public class CountryConfiguration
: EntityTypeConfiguration<Country>
{
public CountryConfiguration()
: base()
{
HasKey(p => p.Id);
Property(p => p.Id)
.HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(p => p.TimeStamp)
.HasColumnName("TimeStamp")
.IsRowVersion();
ToTable("Countries");
}
}
public class CurrencyConfiguration
: EntityTypeConfiguration<Currency>
{
public CurrencyConfiguration()
: base()
{
HasKey(p => p.Id);
Property(p => p.Id)
.HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(p => 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 => 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 => 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();
}
}
}