2

我使用EntityFramework作为ORM,并且我有两个代表值对象和实体对象模式(Evans)的基类的简单POCO域模型。这两个模式都是关于两个对象的平等,所以我重写了Equals和GetHashCode方法。下面是这两个类:实体框架4.0和DDD模式

public abstract class EntityObject<T>{ 
     protected T _ID = default(T); 

     public T ID { 
      get { return _ID; } 
      protected set { _ID = value; } 
     } 

     public sealed override bool Equals(object obj) { 
      EntityObject<T> compareTo = obj as EntityObject<T>; 
      return (compareTo != null) && 
      ((HasSameNonDefaultIdAs(compareTo) || 
      (IsTransient && compareTo.IsTransient)) && 
      HasSameBusinessSignatureAs(compareTo)); 
     }  

     public virtual void MakeTransient() { 
      _ID = default(T);    

     } 

     public bool IsTransient { 
      get { 
       return _ID == null || _ID.Equals(default(T)); 
      } 
     } 

     public override int GetHashCode() { 
      if (default(T).Equals(_ID)) 
       return 0; 
      return _ID.GetHashCode(); 
     } 

     private bool HasSameBusinessSignatureAs(EntityObject<T> compareTo) { 
      return ToString().Equals(compareTo.ToString()); 
     } 

     private bool HasSameNonDefaultIdAs(EntityObject<T> compareTo) { 
      return (_ID != null && !_ID.Equals(default(T))) && 
      (compareTo._ID != null && !compareTo._ID.Equals(default(T))) && 
      _ID.Equals(compareTo._ID); 
     } 

     public override string ToString() { 
      StringBuilder str = new StringBuilder(); 
      str.Append(" Class: ").Append(GetType().FullName); 
      if (!IsTransient) 
       str.Append(" ID: " + _ID); 
      return str.ToString(); 
     } 
    } 

public abstract class ValueObject<T, U> : IEquatable<T> where T : ValueObject<T, U> { 
     private static List<PropertyInfo> Properties { get; set; } 
     private static Func<ValueObject<T, U>, PropertyInfo, object[], object> _GetPropValue; 

     static ValueObject() { 
      Properties = new List<PropertyInfo>();   
      var propParam = Expression.Parameter(typeof(PropertyInfo), "propParam"); 
      var target = Expression.Parameter(typeof(ValueObject<T, U>), "target"); 
      var indexPar = Expression.Parameter(typeof(object[]), "indexPar");    
      var call = Expression.Call(propParam, typeof(PropertyInfo).GetMethod("GetValue", new[] { typeof(object), typeof(object[]) }), 
       new[] { target, indexPar }); 
      var lambda = Expression.Lambda<Func<ValueObject<T, U>, PropertyInfo, object[], object>>(call, target, propParam, indexPar); 
      _GetPropValue = lambda.Compile();        
     } 

     public U ID { get; protected set; }   

     public override Boolean Equals(Object obj) { 
      if (ReferenceEquals(null, obj)) return false; 
      if (obj.GetType() != GetType()) return false; 
      return Equals(obj as T); 
     } 

     public Boolean Equals(T other) { 
      if (ReferenceEquals(null, other)) return false; 
      if (ReferenceEquals(this, other)) return true; 
      foreach (var property in Properties) { 
       var oneValue = _GetPropValue(this, property, null); 
       var otherValue = _GetPropValue(other, property, null); 
       if (null == oneValue && null == otherValue) return false; 
       if (false == oneValue.Equals(otherValue)) return false; 
      } 
      return true; 
     } 

     public override Int32 GetHashCode() { 
      var hashCode = 36; 
      foreach (var property in Properties) { 
       var propertyValue = _GetPropValue(this, property, null);    
       if (null == propertyValue) 
        continue; 
       hashCode = hashCode^propertyValue.GetHashCode(); 
      } 
      return hashCode; 
     } 

     public override String ToString() { 
      var stringBuilder = new StringBuilder(); 
      foreach (var property in Properties) { 
       var propertyValue = _GetPropValue(this, property, null); 
       if (null == propertyValue) 
        continue; 
       stringBuilder.Append(propertyValue.ToString()); 
      } 
      return stringBuilder.ToString(); 
     } 

     protected static void RegisterProperty(Expression<Func<T, Object>> expression) {   
      MemberExpression memberExpression; 
      if (ExpressionType.Convert == expression.Body.NodeType) { 
       var body = (UnaryExpression)expression.Body; 
       memberExpression = body.Operand as MemberExpression; 
      } 
      else 
       memberExpression = expression.Body as MemberExpression; 
      if (null == memberExpression) 
       throw new InvalidOperationException("InvalidMemberExpression");   
      Properties.Add(memberExpression.Member as PropertyInfo); 
     } 
    } 

一切正常,直到我试图删除一些有关的对象(聚合根对象与被标记为删除级联的两个相依的对象):我有一个例外,“这种关系可能不会被更改,因为一个或多个外键属性是不可空的“。我GOOGLE了这个,发现http://blog.abodit.com/2010/05/the-relationship-could-not-be-changed-because-one-or-more-of-the-foreign-key-properties-is-non-nullable/ 我改变了GetHashCode为base.GetHashCode()并且错误消失了。但现在它破坏了我所有的代码:我无法为我的POCO对象重写GetHashCode =>我无法覆盖Equals =>我无法为我的POCO对象实现Value Object和Entity Object模式。所以,我很欣赏任何解决方案,这里的解决方法等。

回答

0

如果你想重写GetHashCode,你必须直接解决问题。问题赛斯:

"The relationship could not be changed because one or more of the foreign-key properties is non-nullable" 

所以,
1.找到用作外键不可为空场,并使其可为空(所以当你删除的记录 - 在FK可以为空)。
2.不要将依赖项标记为级联删除。