以下可能有效。
myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).State = EntityState.Modified;
var objectContext = ((IObjectContextAdapter) myDbContext).ObjectContext;
foreach (var entry in objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Where(entity => entity.Entity.GetType() == typeof(Dogs)))
{
// You need to give Foreign Key Property name
// instead of Navigation Property name
entry.RejectPropertyChanges("OwnerID");
}
myDbContext.SaveChanges();
如果要在一行中完成,请使用以下扩展方法:
public static void DontUpdateProperty<TEntity>(this DbContext context, string propertyName)
{
var objectContext = ((IObjectContextAdapter) context).ObjectContext;
foreach (var entry in objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Where(entity => entity.Entity.GetType() == typeof(TEntity)))
{
entry.RejectPropertyChanges(propertyName);
}
}
并像这样使用它
// After you modify some POCOs
myDbContext.DontUpdateProperty<Dogs>("OwnerID");
myDbContext.SaveChanges();
如您所见,您可以修改此解决方案以满足您的需要,例如使用string[] properties
而不是string propertyName
作为参数。
建议的方法
更好的解决方案是按照您的建议使用属性([NeverUpdate])。要使其工作,您需要使用 SavingChanges 事件(查看我的博客):
void ObjectContext_SavingChanges(object sender, System.Data.Objects.SavingChangesEventArgs e)
{
ObjectContext context = sender as ObjectContext;
if(context != null)
{
foreach(ObjectStateEntry entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
{
var type = typeof(entry.Entity);
var properties = type.GetProperties();
foreach( var property in properties )
{
var attributes = property.GetCustomAttributes(typeof(NeverUpdateAttribute), false);
if(attributes.Length > 0)
entry.RejectPropertyChanges(property.Name);
}
}
}
}
// Check Microsoft documentation on how to create custom attributes:
// http://msdn.microsoft.com/en-us/library/sw480ze8(v=vs.80).aspx
public class NeverUpdateAttribute: SystemAttribute
{
}
//In your POCO
public class Dogs
{
[NeverUpdate]
public int OwnerID { get; set; }
}
警告:我没有编译这段代码。我不在家 :/
警告 2:我刚刚阅读了MSDN 文档,上面写着:
ObjectStateEntry.RejectPropertyChanges 方法
拒绝自上次加载、附加、保存或接受更改以来对具有给定名称的属性所做的任何更改。该属性的原始值被存储,该属性将不再被标记为已修改。
我不确定在附加修改实体的情况下它的行为是什么。我明天试试这个。
警告 3:我现在已经尝试过了。此解决方案有效。被方法拒绝的属性RejectPropertyChanges()
不会在持久性单元(数据库)中更新。
但是,如果更新的实体是通过调用附加的Attach()
,则当前上下文在之后仍然是脏的SaveChanges()
。假设数据库中存在以下行:
Dogs
ID: 1
Name: Max
OwnerID: 1
考虑以下代码:
var myDog = new Dogs();
myDog.ID = 1;
myDog.Name = Achilles;
myDog.OwnerID = 2;
myDbContext.Dogs.Attach(myDog);
myDbContext.Entry(myDog).State = EntityState.Modified;
myDbContext.SaveChanges();
SaveChanges() 后数据库的当前状态:
Dogs:
ID: 1
Name: Achilles
OwnerID: 1
SaveChanges() 之后 myDbContext 的当前状态:
var ownerId = myDog.OwnerID; // it is 2
var status = myDbContext.Entry(myDog).State; // it is Unchanged
那你应该怎么做?在 SaveChanges() 之后将其分离:
Dogs myDog = new Dogs();
//Set properties
...
myDbContext.Dogs.Attach(myDog);
myDbContext.Entry(myDog).State = EntityState.Modified;
myDbContext.SaveChanges();
myDbContext.Entry(myDog).State = EntityState.Detached;