EF 4.1 - сначала исключение из коллекции обновлений SQL ce 4.0 с кодом - PullRequest
5 голосов
/ 19 июля 2011

Сначала я использую код EF 4.1 с SQL ce 4.0

У меня есть два класса

public class Customer
{
    public int ID { get; set; }

    public string CompanyName { get; set; }

    public List<ContactPerson> ContactPersons { get; set; }
}

public class ContactPerson
{
    public int ID { get; set; }

    public string Name { get; set; }

}

и DbContext

public class MyDB : DbContext
{
    public DbSet<ContactPerson> ContactPersons { get; set; }

    public DbSet<Customer> Customers { get; set; }

    public MyDB()
    {
        this.Configuration.LazyLoadingEnabled = true;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>()
            .HasMany(c => c.ContactPersons)
            .WithRequired()
            .WillCascadeOnDelete(true);
    }
}

В то же время вкод, который мне нужен для обновления всей коллекции ContactPerson клиента.

List<ContactPersons> modifiedContactPersons;
Customer customer = MyDB.Customers.Find(ID);
customer.ContactPersons = modifiedContactPersons;

когда я вызываю MyDB.SaveChanges (), я получаю следующее исключение:

Произошла ошибкапри сохранении сущностей, которые не предоставляют свойства внешнего ключа для своих отношений.Свойство EntityEntries вернет значение NULL, поскольку один объект не может быть определен как источник исключения.Обработка исключений при сохранении может быть упрощена путем предоставления свойств внешнего ключа в типах объектов.Подробности см. В InnerException.

с InnerException:

Отношение из AssociationSet Customer_ContactPersons находится в состоянии «Удалено».Учитывая ограничения множественности, соответствующий «Customer_ContactPersons_Target» должен также находиться в состоянии «Удалено».

Я понимаю, что это означает, но я не могу решить проблему самостоятельно.Есть предложения?

1 Ответ

8 голосов
/ 19 июля 2011

Проблема в следующем:

customer.ContactPersons = modifiedContactPersons;

Заменяет список старых связанных контактных лиц списком новых связанных контактных лиц и выполняет две операции:

  • Сначалапометить отношения со всеми ранее связанными лицами для Deleted
  • Затем присоединить всех новых контрактных лиц и пометить отношения с ними как Added

Первая операция - проблема, так как удалениеотношение не удаляет связанный объект, поэтому вы получаете ContactPerson, который не связан ни с каким Customer, и это не разрешено вашим отображением (FK не обнуляется).

Решение этой проблемы зависит оттребование, которое вы пытаетесь достичь.Если вы действительно хотите сначала удалить всех связанных лиц, вы должны вручную установить состояние каждого из них, прежде чем назначить новый список.Если вы хотите обновить существующих людей, вы не должны делать это вообще.Вам следует перебирать лиц, связанных с клиентом, и изменять их данные из нового списка.Зачем?Потому что:

  • Если вы удалите сущность и вставите новую вместо обновления существующей, у вас будет два оператора изменения базы данных вместо одного = два обращения к базе данных вместо одного, а в случае многих объектов этосильно замедлит работу вашего приложения
  • Если у вас есть другой объект, зависящий от ContractPerson, вы не можете удалить его.Кроме того, если вы используете ContractPerson Id где-то, и если оно генерируется автоматически, оно больше не будет существовать после удаления исходной записи.
  • Как правило, это ужасно неправильный и ленивый подход.Вставьте новые записи, измените существующие записи и удалите только те записи, которые действительно должны быть удалены.
...