DDD:GetHashCode和主要ID

mbu*_*bue 3 c# domain-driven-design

我已经看到了DDD域实现,其中实体在构建Equals/GetHashCode方法时依赖于主键ID.我理解为什么这是一个好主意,因为主键可能是唯一不可变的成员.但是,也有可能出现这样的情况.

考虑一个字典,保存刚才实例化的实体.主键(假设它是自动递增值,而不是"业务相关"值)尚未分配,每个实体可能为0.现在,将保存Dictionary中的实体.这意味着主键的更改导致不同的哈希码.

我的问题:如果没有与业务相关的主键可用且所有成员都是可变的,那么对于GetHashCode应使用什么模式?

先感谢您.

Fre*_*els 6

在这种情况下,如果已分配Id ,我只依赖于EqualsGetHashcode方法中的Id.在其他情况下,我使用引用比较相等性.这同样适用于与GetHashCode执行; 如果已分配Id,我只根据'Id'创建一个哈希码.(也就是说,如果实体不是短暂的).

下面的代码是我使用的.这有点基于Sharp架构中的实体:

        public override bool Equals( object obj )
        {
            Entity<TId> other = obj as Entity<TId>;

            if( other == null || this.GetType() != other.GetType() )
            {
                return false;
            }

            bool otherIsTransient = Equals (other.Id, default(TId));
            bool thisIsTransient = Equals (this.Id, default (TId));

            if( otherIsTransient && thisIsTransient )
            {
                return ReferenceEquals (this, other);
            }

            return Id.Equals (other.Id);

        }
Run Code Online (Sandbox Code Playgroud)

首先,我检查两个实体是否属于同一类型.(实际上,您也可以通过实现正确的接口来创建此方法的类型化版本(IEquality<T>)当两个实体属于同一类型时,我会检查其中一个是否是瞬态的.我只是通过检查它们的Id属性来做到这一点:如果它包含默认值,则意味着它们尚未保存在数据库中.如果它们都是瞬态的,我会在它们的引用上比较两个实体.否则,我可以在它们的ID上进行比较.

我使用的GetHashCode方法确保返回的值永远不会更改:

        private int? _oldHashCode;

        public override int GetHashCode()
        {
            // Once we have a hash code we'll never change it
            if( _oldHashCode.HasValue )
            {
                return _oldHashCode.Value;
            }

            bool thisIsTransient = Equals (Id, default(TId));


            // When this instance is transient, we use the base GetHashCode()
            // and remember it, so an instance can NEVER change its hash code.

            if( thisIsTransient )
            {
                _oldHashCode = base.GetHashCode ();

                return _oldHashCode.Value;
            }

            return Id.GetHashCode ();
        }
Run Code Online (Sandbox Code Playgroud)