2

J'utilise EntityFramework comme ORM et j'ai un modèle de domaine POCO simple avec deux classes de base qui représentent des objets de valeur et des entités d'objets (Evans). Ces deux modèles sont tous sur l'égalité de deux objets, donc j'ai outrepassé les méthodes Equals et GetHashCode. Voici ces deux classes:Modèles Entity Framework 4.0 et 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); 
     } 
    } 

Tout était OK jusqu'à ce que j'ai essayé de supprimer des objets connexes (agrégat objet racine avec deux objets dépendants qui a été marqué pour la suppression en cascade): J'ai une exception « La relation pourrait ne pas être modifié car une ou plusieurs des propriétés de clé étrangère est non nullable ". J'ai googlé cela et trouvé http://blog.abodit.com/2010/05/the-relationship-could-not-be-changed-because-one-or-more-of-the-foreign-key-properties-is-non-nullable/ J'ai changé GetHashCode en base.GetHashCode() et l'erreur a disparu. Mais maintenant, il casse tout mon code: je ne peux pas redéfinir GetHashCode pour mes objets POCO => Je ne peux pas redéfinir Equals => Je ne peux pas implémenter les objets Objet de valeur et Objet d'entité pour mes objets POCO. Donc, j'apprécie toutes les solutions, solutions de contournement ici

Répondre

0

Si vous voulez remplacer GetHashCode, vous devez résoudre le problème directement. Le problème sais:

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

Ainsi,
1. Trouver le champ non annulable qui a utilisé comme une clé étrangère et de le rendre annulable (donc quand vous supprimez le dossier - fk peut être nul).
2. Ne marquez pas la dépendance comme une suppression en cascade.

Questions connexes