2011-07-19 71 views
5

我使用EF 4.1代碼先用SQL CE 4.0EF 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:

從 'Customer_ContactPersons' AssociationSet的關係是在 的 '已刪除' 狀態。考慮到多重性約束,相應的 'Customer_ContactPersons_Target'也必須處於'已刪除'狀態。

我明白這意味着什麼,但我無法自己解決問題。 有什麼建議嗎?

回答

8

這裏的問題是這樣的:

customer.ContactPersons = modifiedContactPersons; 

它將用新的相關聯繫人列表老相關的聯絡人名單和它兩個操作:

  • 它首先標記關係到所有先前相關人員Deleted
  • 然後附上所有新的合同人並將其與他們的關係標記爲Added

第一個操作是一個問題,因爲刪除關係不會刪除相關的實體,因此最終得到的ContactPersonCustomer無關,並且您的映射不允許(FK不可爲空)。

解決此問題取決於您試圖實現的要求。如果您確實想要首先刪除所有相關人員,則必須先將每個人員的狀態設置爲手動刪除,然後再分配新列表。如果你想更新現有的人,你不應該這樣做。您應該迭代與客戶相關的人員並從新列表中修改其數據。爲什麼?因爲:

  • 如果刪除實體,並插入一個新的,而不是更新現有的您將有兩個數據庫修改語句,而不是一個=兩個往返數據庫之一,在許多實體會慢的情況下,而不是你的應用很多
  • 如果您有任何其他實體依賴於ContractPerson,則無法刪除它。另外,如果您在某處使用ContractPersonId,並且它是自動生成的,則在您刪除原始記錄後它不會再存在。
  • 這通常是非常錯誤和懶惰的方法。插入新記錄,修改現有記錄並只刪除應該真正刪除的記錄。
+0

您寫道:「您應該迭代與客戶相關的人員並從新列表修改其數據。」我如何以最簡單的方式做到這一點? – esba