Свойства Readonly в EF 4.1
Я столкнулся с ситуацией, когда мне нужно иметь свойство readonly EF в случае "оптимистического обновления" (вы не загружаете текущее состояние вашего объекта домена из базы данных, чтобы проверить, какие свойства действительно изменены. как Изменено и обновить его до базы данных. В этом случае вы избегаете избыточных операций выбора и слияния).
Вы не можете написать что-то вроде этого: DataContext.Entry(entity).Property(propertyName).IsModified = false;
, потому что параметр "false" не поддерживается, и вы получите исключение. (в EF 4.1)
Я создал простую структуру для регистрации свойств readonly в репозитории.
Таким образом, вы можете легко изменить только свойства nonreadonly.
Что вы думаете об этом?
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
Это будет работать, но мне не нравится необходимость регистрировать измененные свойства непосредственно в репозитории. Вы можете забыть о зарегистрированных свойствах, и код случайно не сохранит некоторые изменения - это будет ошибка, которая будет трудно найти при повторном использовании репозитория в сложных сценариях. Мне нравится явное определение обновленных свойств каждый раз, когда вы вызываете что-то вроде Update в вашем репозитории. Также мне не нравится отражение в коде. Если вы не измените свой код, чтобы получать отраженные данные о каждом объекте только один раз для всего приложения, вы делаете это неправильно.
Я написал ответ для 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);