Entity framework 如何使用Entity Framework和EntityState更新对象的每个字段。已修改

Entity framework 如何使用Entity Framework和EntityState更新对象的每个字段。已修改,entity-framework,entity-framework-4.1,Entity Framework,Entity Framework 4.1,我需要更新给定实体对象的除property1和property2之外的所有字段。 有此代码: [HttpPost] public ActionResult Add(object obj) { if (ModelState.IsValid) { context.Entry(obj).State = System.Data.EntityState.Modified; contex

我需要更新给定实体对象的除property1和property2之外的所有字段。
有此代码:

    [HttpPost]
    public ActionResult Add(object obj)
    {
        if (ModelState.IsValid)
        {
                context.Entry(obj).State = System.Data.EntityState.Modified;

                context.SaveChanges();               
         }
        return View(obj);
    }

如何将其更改为向obj.property1和obj.property2添加未使用此代码更新的异常

您不能定义这样的异常。但是,您可以将单个特性标记为已修改:

context.Entry(obj).Property(o=>o.Property3).IsModified=true;
context.Entry(obj.Property(o=>o.Property4).IsModified=true;
//等等。
请注意,一旦将整个实体的状态标记为“已修改”,则不支持将
IsModified
设置为
false

出于您的目的,我实际上更希望从数据库加载实体,然后使用常规更改跟踪进行更新:

var objInDB=context.Objects.Single(o=>o.Id==obj.Id);
obj.Property1=objInDB.Property1;
obj.Property2=objInDB.Property2;
context.Entry(objInDB).CurrentValues.SetValues(obj);
SaveChanges();

假设您有一个要排除的属性集合:

var excluded = new[] { "property1", "property2" };
使用.NET 4.5上的EF5,您可以执行以下操作:

var entry = context.Entry(obj);
entry.State = EntityState.Modified;
foreach (var name in excluded)
{
    entry.Property(name).IsModified = false;
}
这使用了.NET 4.5上EF5的一项新功能,该功能允许将属性设置为未修改,即使之前已将其设置为“已修改”

在.NET 4上使用EF 4.3.1或EF5时,您可以改为:

var entry = context.Entry(obj);
foreach (var name in entry.CurrentValues.PropertyNames.Except(excluded))
{
    entry.Property(name).IsModified = true;
}

这个问题已经得到了很好的回答,但我想为任何想使用它的人提供一个扩展方法

本规范是为EF 4.3.1制定的

//You will need to import/use these namespaces    
using System.Data.Entity;
using System.Data.Entity.Infrastructure;    

//Update an entity object's specified columns, comma separated
//This method assumes you already have a context open/initialized
public static void Update<T>(this DbContext context, T entityObject, params string[] properties) where T : class
{
    context.Set<T>().Attach(entityObject);

    var entry = context.Entry(entityObject);

    foreach(string name in properties)
        entry.Property(name).IsModified = true;

    context.SaveChanges();
}
//您需要导入/使用这些名称空间
使用System.Data.Entity;
使用System.Data.Entity.Infrastructure;
//更新实体对象的指定列,以逗号分隔
//此方法假定您已经打开/初始化了上下文
公共静态无效更新(此DbContext上下文、T entityObject、参数字符串[]属性),其中T:class
{
context.Set().Attach(entityObject);
var entry=context.entry(entityObject);
foreach(属性中的字符串名称)
entry.Property(name).IsModified=true;
SaveChanges();
}
用法示例

using (FooEntities context = new FooEntities())
{
    FooEntity ef = new FooEntity();

    //For argument's sake say this entity has 4 columns: 
    //    FooID (PK), BarID (FK), Name, Age, CreatedBy, CreatedOn

    //Mock changes
    ef.FooID = 1;
    ef.Name = "Billy";
    ef.Age = 85;

    context.Update<FooEntity>(ef, "Name", "Age"); //I only want to update Name and Age
}
使用(FooEntities上下文=新的FooEntities())
{
FooEntity ef=新的FooEntity();
//为了便于讨论,假设该实体有4列:
//FooID(PK)、BarID(FK)、姓名、年龄、CreatedBy、CreatedOn
//模拟变化
ef.FooID=1;
ef.Name=“比利”;
ef.年龄=85岁;
Update(ef,“Name”,“Age”);//我只想更新Name和Age
}
以上答案(大多数)使用DbContext。对于那些使用ObjectContext的人来说,这些解决方案是不可访问的

以下是严格意义上的ObjectContext解决方案(EF5.NET 4.5):


这是一个适用于.net CORE的更新,可能可以帮助需要通用解决方案并希望根据不同条件排除某些属性的人

我使用反射遍历属性并根据其属性值更新base,在本例中,我排除了null属性

    public virtual TEntity Update(TEntity entity)
    {
        dbSet.Attach(entity);
        dbContext.Entry(entity).State = EntityState.Modified;

        var entry = dbContext.Entry(entity);

        Type type = typeof(TEntity);
        PropertyInfo[] properties = type.GetProperties();
        foreach (PropertyInfo property in properties)
        {
            if (property.GetValue(entity, null) == null)
            {
                entry.Property(property.Name).IsModified = false;
            }
        }

        dbContext.SaveChanges();
        return entity;
    }

是 啊在.Net 4.5中这是一个很好的实现,我知道这是隐含的,但我只想明确指出,对于EF 4.3.1,您不能设置entry.Property(…).IsModified=false;-它将被编译,但在尝试执行此操作时,将出现运行时错误。因此,我认为有必要说,对于EF 4.3.1,您必须只使用正数,换句话说:您只能将事物标记为已修改(true),因为它们已经设置为未修改(false)。EF 5允许您自由设置真/假;在.NET4.5上,这是一个多么棒的解决方案,我在IUnitOfWork+DI实现中使用了它,它真的令人印象深刻,谢谢@Arthur-它应该像“entry.Property(obj.name).IsModified=false”那样工作吗?很好!同样适用于EF core 2.2.4。我喜欢你的第二个代码块,这是一个很好的不使用false语句的反向解决方案。+1用于以下内容:“注意,一旦你将整个实体的状态标记为修改状态,就不支持将IsModified设置为false。”我注意到这里有一个类似的注释:即“当前无法将标记为已修改的单个属性重置为未修改。这是我们计划在未来的版本中支持的内容。“然而,当我尝试它时,它起了作用。也许msdn页面已经过时,尽管它说它是在2016年10月23日更新的。
    public virtual TEntity Update(TEntity entity)
    {
        dbSet.Attach(entity);
        dbContext.Entry(entity).State = EntityState.Modified;

        var entry = dbContext.Entry(entity);

        Type type = typeof(TEntity);
        PropertyInfo[] properties = type.GetProperties();
        foreach (PropertyInfo property in properties)
        {
            if (property.GetValue(entity, null) == null)
            {
                entry.Property(property.Name).IsModified = false;
            }
        }

        dbContext.SaveChanges();
        return entity;
    }