【问题标题】:Value equality comparisons on new objects新对象的值相等比较
【发布时间】:2009-04-08 20:02:43
【问题描述】:

我在一个抽象基类中重写了 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 方法中,我正在检查以确保集合尚未包含要添加的对象。如果所有新添加的对象都相等,那么我永远无法将两个新对象添加到集合中。

【问题讨论】:

    标签: c# .net oop domain-driven-design


    【解决方案1】:

    NHibernate 保证与相同上下文关联的实体的对象引用标识与数据库标识相同。所以不需要重写 Equals() 和 GetHashCode(),因为这是你要实现的同一个身份。

    参见NHibernate Reference Documentation 中的10.3. Considering object identity

    此外,使用数据库生成的键与上下文相关联的新实体应立即将实体持久保存到数据库并将实体的键设置为生成的键。

    【讨论】:

    • 好点...我认为我不会在 ISession 之间保留任何集合引用。
    【解决方案2】:

    您应该在构造函数中获取您的 ID,或者至少是某种标识符。

    如果没有设置ID(或者是默认值);显然,对于任何相同类型的对象(也没有设置 ID),Equals 方法都会返回 true。

    【讨论】:

      【解决方案3】:

      如果 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);
      }
      

      【讨论】:

        【解决方案4】:

        有一个主要细节会影响您的决定:

        ...我想实现相同的 其他项目使用的模式 int ids...

        通常,ID 会在数据库中生成以强制唯一性。现在您有了 GUID,您不必依赖数据库来生成值 - GUID 保证是唯一的。不要因为错误的原因而遵循模式:)

        所以继续在构造函数中创建 GUID 值 - 只需确保有一个设置器,以便 NHibernate 在从数据库中获取实体时可以覆盖该值。

        此外,如果您的 DBA 关心 GUID 和数据库碎片,您可能需要考虑使用 COMB GUIDs

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-13
          • 2021-10-10
          相关资源
          最近更新 更多