代码之家  ›  专栏  ›  技术社区  ›  Voice

实体框架4.0和DDD模式

  •  2
  • Voice  · 技术社区  · 14 年前

    我使用EntityFramework作为ORM,我有一个简单的POCO域模型,它有两个基类,分别表示值对象和实体对象模式(Evans)。这两种模式都是关于两个对象的相等,所以我重写了Equals和GetHashCode方法。以下是两个课程:

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

    在我尝试删除一些相关对象之前,一切都正常(聚合根对象和两个标记为级联删除的从属对象):我遇到了一个异常“关系无法更改,因为一个或多个外键属性不可为null”。我在谷歌上搜索了一下,发现 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对象实现值对象和实体对象模式。所以,我很感激这里的任何解决方案和变通办法。

    1 回复  |  直到 14 年前
        1
  •  0
  •   Naor    13 年前

    如果你想覆盖GetHashCode,你必须直接解决这个问题。问题是:

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

    所以
    1.找到用作外键的不可空字段,并将其设置为可空(因此,当删除记录时,fk可以为空)。
    2.不要将依赖项标记为级联删除。