EF 4.1代码优先SQL ce 4.0更新集合异常

时间:2011-07-19 09:18:03

标签: entity-framework-4.1 ef-code-first sql-server-ce-4

我首先在SQL ce 4.0中使用EF 4.1代码

我有两个班级

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:

  

来自'Customer_ContactPersons'AssociationSet的关系在   '已删除'状态。给定多重约束,相应的   'Customer_ContactPersons_Target'也必须处于'已删除'状态。

我明白这意味着什么,但我不能自己解决问题。 有什么建议吗?

1 个答案:

答案 0 :(得分:8)

问题在于:

customer.ContactPersons = modifiedContactPersons;

它将新的相关联系人列表替换为新的相关联系人列表,并进行两项操作:

  • 首先标记与Deleted
  • 之前所有相关人员的关系
  • 然后附上所有新合同,并将其标记为Added

第一个操作是一个问题,因为删除关系不会删除相关实体,因此您最终得到的ContactPerson与任何Customer无关,并且您的映射不允许它(FK是不可空的。)

解决此问题取决于您尝试实现的要求。如果您确实要首先删除所有相关人员,则必须在分配新列表之前手动将每个人员的状态设置为已删除。如果您想更新现有人员,则根本不应该这样做。您应该迭代与客户相关的人员并从新列表中修改他们的数据。为什么?这是因为:

  • 如果您删除实体并插入一个新实体而不是更新现有实体,您将有两个数据库修改语句而不是一个=两个往返于数据库的往返而不是一个,如果有很多实体,它将大大减慢您的应用程序
  • 如果您有任何其他依赖于ContractPerson的实体,则无法将其删除。此外,如果您在某处使用ContractPerson的{​​{1}},并且如果它是自动生成的,则在您删除原始记录后它将不再存在。
  • 这通常是非常错误和懒惰的方法。插入新记录,修改现有记录,只删除真正应删除的记录。