2009-04-08 87 views
1

我已經重寫了抽象基類中的Equals和GetHashCode以基於對象的關鍵屬性實現值相等性。我的主要目的是能夠在集合上使用Contains方法而不是Find或FirstOrDefault來檢查實例是否已經添加到集合中。新對象的值相等性比較

public abstract class Entity 
{ 
    public abstract Guid Id { get; } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
     { 
      return false; 
     } 

     if (obj.GetType() != GetType()) 
     { 
      return false; 
     } 

     var entity = (Entity)obj; 
     return (entity.Id == Id); 
    } 

    public override int GetHashCode() 
    { 
     return Id.GetHashCode(); 
    } 

} 

這種方法的問題是,我們的所有對象在被持久化並獲得一個Id(由NHibernate生成)之前是相等的。我做錯了嗎?我可以在構造函數中生成Id,但是我想爲其他使用int id的項目實現相同的模式,所以顯然不起作用。

在我看來,覆蓋Equals的任何對象都將在對象實例化後立即與同一對象的任何其他實例相等。

編輯補充: 這裏是與我有關的場景:在Add方法對我的收藏,我檢查,以確保該集合尚未包含要添加的對象。如果所有新建的對象都是相同的,那麼我永遠不會向集合添加兩個新對象。

回答

2

NHibernate保證與相同上下文關聯的實體的對象引用標識與數據庫標識相同。所以不需要重寫Equals()和GetHashCode(),因爲這是你想要實現的同一個身份。

請參閱NHibernate Reference Documentation10.3. Considering object identity

此外,使用數據庫生成的密鑰與上下文相關聯的新實體應該立即將實體持久存儲到數據庫,並將實體的密鑰設置爲生成的密鑰。

+0

好點...我不認爲我會在ISessions之間保留任何集合引用。 – 2009-04-08 23:09:11

1

您應該在構造函數中獲得您的ID或至少某種標識符。

如果沒有設置ID(或者是默認值);顯然Equals方法將返回任何相同類型的對象(也沒有設置ID)的true。

+0

直到我嘗試過,這對我來說並不明顯,謝謝。 – 2009-04-08 23:06:34

0

如果Id未初始化,返回「不等於」會有幫助嗎?

public override bool Equals(object obj) 
{ 
    if (obj == null) 
    { 
     return false; 
    } 

    if (obj.GetType() != GetType()) 
    { 
     return false; 
    } 

    var entity = (Entity)obj; 
    if ((Id == Guid.Empty) || (entity.Id == Guid.Empty)) 
    { 
     return false; 
    } 
    return (entity.Id == Id); 
} 
0

有會影響你的決定的一個主要細節:

...我想實現對使用 INT IDS等項目一樣 模式...

通常,在數據庫中生成ID以強制執行唯一性。既然您擁有GUID,您就不必依靠數據庫來生成值 - GUID保證是唯一的。不要因爲錯誤原因遵循模式:)

因此,請繼續在構造函數中創建GUID值 - 只要確保有一個setter,以便NHibernate在從數據庫中獲取實體時可以覆蓋該值。

此外,如果您的DBA擔心GUID和數據庫碎片,您可能需要考慮使用COMB GUIDs