在实体框架中排除更新属性

时间:2012-09-30 14:13:08

标签: c# asp.net-mvc entity-framework

在MVC中更新模型时,我一直在寻找一种标记属性的正确方法。

例如,让我们采用这个小模型:

class Model
{
    [Key]
    public Guid Id {get; set;}
    public Guid Token {get; set;}

    //... lots of properties here ...
}

然后编辑方法MVC创建如下:

[HttpPost]
public ActionResult Edit(Model model)
{
    if (ModelState.IsValid)
    {
        db.Entry(model).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(model);
}

现在如果我的View不包含令牌,它将通过该编辑无效。

我正在寻找类似的东西:

db.Entry(model).State = EntityState.Modified;
db.Entry(model).Property(x => x.Token).State = PropertyState.Unmodified;
db.SaveChanges();

到目前为止,我发现的最好的方法是包容性并设置我想要包含的所有属性,但我真的只想说哪些属性被排除在外。

5 个答案:

答案 0 :(得分:118)

我们可以像这样使用

 db.Entry(model).State = EntityState.Modified;
 db.Entry(model).Property(x => x.Token).IsModified = false;
 db.SaveChanges();

它会更新但没有令牌属性

答案 1 :(得分:7)

创建新模型,该模型将具有您想要更新的有限属性集。

即。如果您的实体模型是:

public class User
{
    public int Id {get;set;}
    public string Name {get;set;}
    public bool Enabled {get;set;}
}

您可以创建允许用户更改名称的自定义视图模型,但不能更改已启用标记:

public class UserProfileModel
{
   public int Id {get;set;}
   public string Name {get;set;}
}

如果要进行数据库更新,请执行以下操作:

YourUpdateMethod(UserProfileModel model)
{
    using(YourContext ctx = new YourContext())
    { 
        User user = new User { Id = model.Id } ;   /// stub model, only has Id
        ctx.Users.Attach(user); /// track your stub model
        ctx.Entry(user).CurrentValues.SetValues(model); /// reflection
        ctx.SaveChanges();
    }
}

调用此方法时,您将更新名称,但Enabled属性将保持不变。我使用的是简单模型,但我想你会得到如何使用它的图片。

答案 2 :(得分:3)

寻找如何在EF Core上实现此目标的任何人。基本上是相同的,但是您需要在添加要更新的模型之后将IsModified设置为

db.Update(model);
db.Entry(model).Property(x => x.Token).IsModified = false;
db.SaveChanges();

答案 3 :(得分:1)

我想您不希望在某些情况下更改属性,因为如果您不打算在应用程序中使用它,只需将其从模型中删除即可。

如果你想在某些情况下使用它并避免在上面的情况下“无效”,你可以尝试:

  • 使用HiddenFor:

    隐藏视图中的参数

    @Html.HiddenFor(m => m.Token)

这将使您的原始值保持不变,并传递回控制器。

DBSet再次加载控制器中的对象并运行此方法。您可以指定白名单和不应更新的参数黑名单。

答案 4 :(得分:1)

我提供了一种简单的方法来编辑我将与您分享的实体的属性。 此代码将编辑实体的名称和族属性:

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Take, nameof(profileInfo.Name), nameof(profileInfo.Family));
        }
    }

此代码将忽略编辑实体的名称和族属性,它将编辑另一个属性:

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Ignore, nameof(profileInfo.Name), nameof(profileInfo.Family));
        }
    }

使用此扩展程序:

public static void EditEntity<TEntity>(this DbContext context, TEntity entity, TypeOfEditEntityProperty typeOfEditEntityProperty, params string[] properties)
   where TEntity : class
{
    var find = context.Set<TEntity>().Find(entity.GetType().GetProperty("Id").GetValue(entity, null));
    if (find == null)
        throw new Exception("id not found in database");
    if (typeOfEditEntityProperty == TypeOfEditEntityProperty.Ignore)
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            if (properties.Contains(item.Name))
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    else if (typeOfEditEntityProperty == TypeOfEditEntityProperty.Take)
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            if (!properties.Contains(item.Name))
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    else
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    context.SaveChanges();
}

public enum TypeOfEditEntityProperty
{
    Ignore,
    Take
}