加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 调用SaveChanges()时从更新中排除属性

发布时间:2020-12-16 03:54:17 所属栏目:asp.Net 来源:网络整理
导读:似乎有两种方法使用“attach”方法更新断开连接的Entity Framework实体. 方法一是简单地将断开连接的实体的状态设置为已修改: myDbContext.Dogs.Attach(dog);myDbContext.Entry(dog).State = EntityState.Modified;myDbContext.SaveChanges(); 这将保存“do
似乎有两种方法使用“attach”方法更新断开连接的Entity Framework实体.

方法一是简单地将断开连接的实体的状态设置为已修改:

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).State = EntityState.Modified;
myDbContext.SaveChanges();

这将保存“dog”对象上的所有字段.但是你说你是在一个mvc网页上做的,你只允许编辑Dog.Name,页面上唯一的Dog属性是Name.然后可以做方法二:

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).Property(o => o.Name).CurrentValue = dog.Name;
myDbContext.Entry(dog).Property(o => o.Name).IsModified = true;
myDbContext.SaveChanges();

当有许多属性需要更新时,方法二可能会变得非常冗长.这促使我尝试方法三,在我不想改变的属性上设置IsModified = false.这不起作用,抛出运行时错误“不支持修改属性的设置IsModified为false”:

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).State = EntityState.Modified;
myDbContext.Entry(dog).Property(o => o.Owner).IsModified = false;
myDbContext.SaveChanges();

我更喜欢在任何地方使用Method One,但是在很多情况下我的asp.net mvc视图不包含Dog类的每个标量属性.

我的问题是:

>我是否可以在POCO类中使用任何属性来告诉Entity Framework我从不希望该属性更新?例如,[NeverUpdate].我知道[NotMapped]属性,但这不是我需要的.
>如果失败了,我有什么方法可以使用上面的方法一(myDbContext.Entry(dog).State = EntityState.Modified;
)并排除我不想更新的字段?

附:我知道另一种方法,不使用“附加”,只需从数据库中获取一个新对象,更新所需的属性,然后保存.这就是我正在做的事情,但我很好奇是否有一种方法可以使用“附加”,从而避免额外的数据库访问,但这样做的方式不像上面的方法二那么冗长.通过“获取一个新鲜的对象”我的意思是:

Dog dbDog = myDbContext.Dogs.FirstOrDefault(d => d.ID = dog.ID);
dbDog.Name = dog.Name;
myDbContext.SaveChanges();

解决方法

以下可能有效.

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 []属性而不是字符串propertyName作为参数.

建议的方法

更好的解决方案是使用您建议的属性([NeverUpdate]).要使其工作,您需要使用SavingChanges事件(检查我的blog):

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 documentation,它说:

ObjectStateEntry.RejectPropertyChanges Method

Rejects any changes made to the property with the given name since the
property was last loaded,attached,saved,or changes were accepted.
The orginal value of the property is stored and the property will no
longer be marked as modified.

我不确定在附加修改后的实体时它的行为是什么.我明天会试试.

警告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;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读