在遇到'乐观更新'的情况下我需要拥有EF readonly属性时(我没有从数据库加载域对象的当前状态以检查实际更改了哪些属性)我遇到了这种情况。您只需设置对象as Modified并将其更新到数据库。在这种情况下,您可以避免冗余的选择和合并操作。)
你不能这样写:DataContext.Entry(entity).Property(propertyName).IsModified = false;
,因为不支持设置'false'值,你会得到一个例外。 (在EF 4.1中)
我创建了一个简单的结构,用于在存储库中注册readonly属性。 因此,您可以轻松修改非易读属性。
您如何看待这个?
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;
}
}
答案 0 :(得分:17)
这样可行,但我不喜欢直接在存储库中注册修改后的属性。您可以忘记已注册的属性和代码将意外地保存一些更改 - 这将是在复杂方案中重用存储库时很难找到的错误。每次在存储库上调用Update之类的东西时,我都喜欢明确定义更新的属性。我也不喜欢代码中的反射。除非您修改代码以仅针对整个应用程序获取有关每个实体的反射数据,否则您做错了。
我写了answer for 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);