EF 4.1中的只读属性

5
我曾经遇到这样的情况,需要在“乐观更新”情况下拥有EF只读属性(您不需要从数据库加载当前状态的域对象来检查哪些属性实际上已更改。您只需将对象设置为已修改,并将其更新到数据库中。在这种情况下,您可以避免冗余的选择和合并操作)。
您不能像这样编写代码:DataContext.Entry(entity).Property(propertyName).IsModified = false;,因为不支持设置“false”值,您会收到异常(在EF 4.1中)。
我创建了一个简单的结构来注册只读属性在存储库中。因此,您可以轻松地修改非只读属性。
您对此有何看法?
public abstract class RepositoryBase<T> where T : class
{   
 private const string MethodReferenceErrorFormat = "Expression '{0}' refers to a method, not a property.";
 private const string FieldReferenceErrorFormat = "Expression '{0}' refers to a field, not a property.";

 protected IList<PropertyInfo> _readOnlyProperties;
        /// <summary>
        /// This method is used to register readonly property for Entity.
        /// </summary>
        /// <param name="propertyLambda">Entity property as LambdaExpression</param>
        protected void RegisterReadOnlyProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
        {
            Guard.ArgumentNotNull(propertyLambda, "propertyLambda");

            var propertyMember = propertyLambda.Body as MemberExpression;
            if (propertyMember == null)
            {
                var exceptionMessage = string.Format(MethodReferenceErrorFormat, propertyLambda);
                throw new ArgumentException(exceptionMessage);
            }

            var propertyInfo = propertyMember.Member as PropertyInfo;
            if (propertyInfo == null)
            {
                var exceptionMessage = string.Format(FieldReferenceErrorFormat, propertyLambda);
                throw new ArgumentException(exceptionMessage);
            }

            _readOnlyProperties.Add(propertyInfo);
        }

         /// <summary>
         /// This method is used to attach domain object to DbContext and mark it as modified to save changes.
         /// </summary>
         /// <param name="entity">Detached entity</param>
        public void SetModified(T entity)
        {
            Guard.ArgumentNotNull(entity, "entity");

            //Mark whole entity as Modified, when collection of readonly properties is empty.
            if(_readOnlyProperties.Count == 0)
            {
                DataContext.Entry(entity).State = EntityState.Modified;
                return;
            }

             //Attach entity to DbContext.
             _dbSet.Attach(entity);

            //Mark all properties except readonly as Modified.
            var allProperties = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            var propertiesForUpdate = allProperties.Except(_readOnlyProperties);
            foreach (var propertyInfo in propertiesForUpdate)
            {
                DataContext.Entry(entity).Property(propertyInfo.Name).IsModified = true;
            }
        }
1个回答

20
这个方案可行,但我不喜欢需要直接在仓库中注册修改后的属性。你可能会忘记已注册的属性,代码将意外地没有保存某些更改 - 这将是一个难以在复杂场景中重用仓库时找到的错误。我喜欢每次调用类似于您的存储库上的更新时明确定义更新后的属性。另外,我不喜欢代码中的反射。除非您修改代码以一次为整个应用程序获取有关每个实体的反射数据,否则您正在错误地执行操作。
我写了EFv4的答案,但可以轻松修改为EFv4.1:
public void Update(T entity, params Expression<Func<T, object>>[] properties)
{
    _dbSet.Attach(entity);
    DbEntityEntry<T> entry = _context.Entry(entity);
    foreach (var selector in properties)
    {
        entry.Property(selector).IsModified = true;
    }
}

你会这样调用它:
repo.Update(entity, e => e.Name, e => e.Description);

当我使用它时,它会给我以下错误:“无法将Lambda表达式转换为类型'Expression<Func<RequestDetail, object>> []',因为它不是委托类型”。 - Imran Rizvi
喜欢它 - 超级简单。对于那些想知道的人,它在EF6上也可以工作。 - dalcam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接