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.不要將依賴項標記爲級聯刪除。