2011-06-23 99 views
8

我在將一個新的對象圖形置於具有一對多關係的上下文時遇到問題。我正在使用Entity Framework 4.1發行版,並實施了Code-First方法。我正在使用現有的SQL 2008數據庫並實現了從DbContext派生的上下文。我有兩個班級,人員和地址。一個人可以包含0個或更多地址,如此定義。實體框架4.1代碼優先並插入新的一對多關係

public class Person 
    { 
     public Person() 
     { 
      Addresses = new List<Address>(); 
     } 

     public int PersonId { get; set; } 
     ***Additional Primitive Properties*** 

     public virtual ICollection<Address> Addresses { get; set; } 

    } 

public class Address 
    { 
     public int AddressId { get; set; } 
     public int AddressTypeId { get; set; } 
     ***Additional Primitive Properties*** 

     public int PersonId { get; set; } 
     public virtual Person Person { get; set; } 
    } 

我想創建一個具有兩個地址的Person的新實例。但是,當我將此結構添加到上下文並保存時,只會保留集合中的第一個地址。第二個將Person導航屬性設置爲null,並且不與Person對象關聯,但是,列表中的第一個關聯。

var person = new Person(); 

var mailingAddress = new Address() { AddressTypeId = 1 }; 
person.Addresses.Add(mailingAddress); 

var billingAddress = new Address() { AddressTypeId = 2 }; 
person.Addresses.Add(billingAddress); 

context.People.Add(entity); 
context.SaveChanges(); 

它不會拋出異常,但地址集合中的第二項只是未保存。

有沒有人有什麼好的想法,爲什麼只有第一個會被保存?謝謝。

+2

您正在創建一個'person',但是將'entity'添加到DbSet。一個錯字? – Slauma

+1

很好的觀察,但那只是一個錯字。 – connr

回答

10

後故障排除/試錯的時間,我已經解決了我的問題。 我的POCO類也用於斷開連接的環境,其中 對象與上下文分離,修改,然後重新連接。

爲了確定哪些導航屬性收集項目受到影響,我覆蓋Address類中的Equals和GetHashCode方法以確定相等性。顯然這會影響EF 4.1插入導航屬性對象的完整集合的能力嗎?

這裏是原始平等方法造成的問題:

public override bool Equals(object obj) 
{ 
    Address address = obj as Address; 
    if (address == null) return false; 
    return address.AddressId == this.AddressId; 
} 

public override int GetHashCode() 
{ 
    return this.AddressId.GetHashCode(); 
} 

爲了糾正這個問題,我創建了導航對象的自定義相等比較 而不是直接把它放置在地址類。

public class AddressEqualityComparer : IEqualityComparer<Address> 
{ 
    public bool Equals(Address address1, Address address2) 
    { 
     if (address1.AddressId == address2.AddressId) 
      return true; 
     else 
      return false; 
    } 

    public int GetHashCode(Address address) 
    { 
     return address.AddressId.GetHashCode(); 
    } 
} 

我做了這個改變後,我的context.People.Add方法調用按預期工作。

如果有人知道爲什麼重寫類中的平等方法會導致EF 4.1只在插入集合中的第一個項目,那將是 很棒的信息。

+1

有趣。我可以重現這一點,只有當你重寫* both *方法時纔會出現問題。無法準確解釋發生了什麼問題,但一個關鍵的問題就是你實現了'GetHashCode'。問題在於,它不表示對象生命期間的對象標識,因爲當您創建並添加對象時,「AddressId」爲0,但是當您調用SaveChanges時,Id將更改爲非0的值。因此,同一對象突然出現另一個HashCode與你的覆蓋。當對象存儲在可能在EF內部的字典中時,這很糟糕。 – Slauma

+0

當遇到這個問題時,我只是添加了我自己的輔助哈希代碼方法,並保留標準.Net一個。這樣做的一個好處是,您可以將這些散列實際存儲在數據庫中進行快速部分比較,如「這30個字段行中的任意兩個之間的這20個字段是否相同?」 –

+0

這是因爲EF將處理foreignkey集合,並通過比較導航集合中的對象來避免重複。在你的情況下,所有的Address實例都是新的,並且Id = 0,並且通過比較id來覆蓋'equal'方法,所以EF認爲你的實例是完全相同的,然後剝離其他實例,但是第一個實例不在其中。希望這解釋得很好。 – iNc0ming

0

這是另一種嘗試添加代碼的方法。值得一試。這段代碼可能不準確,我徒手輸入。

var person = new Person(); 

person.Addresses.Add(new Address() 
{ 
    AddressTypeId = 1 
}), 
new Address() 
{ 
    AddressTypeId = 2 
}); 

context.People.Add(entity); 
context.SaveChanges(); 
+0

感謝您的建議,但我嘗試過,仍然沒有骰子。它將第一個保存在列表中,但沒有後續項目。 – connr

+0

@connr - 您是否在context.People.Add(entity)行放置了一個斷點,並確保在保存更改前有兩個地址。只是要嘗試。 HTH – webtrifusion

+0

是的。地址集合在保存之前和之後有兩個項目。但是在保存之後,Addresses [0] .PersonId = 63和Addresses [1] .PersonId = 0,其中63是新插入的Person行的標識。就好像該集合中的第二個地址僅僅被上下文忽略。謝謝。 – connr

1

正如已經暗示的那樣,這是因爲GetHashCode方法正在使用所有兄弟的ID,在實體框架進行比較時它將爲0。只要評論一下,你就會很開心。

我有同樣的確切問題,這件作品讓我這樣做。我甚至懶得去看看我的EntityBase代碼......它太老了,直到現在一直沒有改變。

非常感謝您的研究!

相關問題