Исключить свойство при обновлении в 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);
}

Теперь, если мое представление не содержит токен, он будет аннулирован через это редактирование.

Я ищу что-то вроде этого:

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

лучший способ я нашел, чтобы быть включено и установить все свойства я хочу включить вручную, но я действительно только хочу сказать, какие из них должны быть исключены.

4 51

4 ответа:

мы можем использовать такой

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

он будет обновляться, но без свойства токена

создать новую модель, которая будет иметь ограниченный набор свойств, которые вы хотите обновить.

т. е. если ваша модель сущности:

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();
    }
}

при вызове этого метода вы обновите имя, но включенное свойство останется неизменным. Я использовал простые модели, но я думаю, вы получите картину, как его использовать.

Я думаю, вы не хотите, чтобы свойство было изменено только в некоторых случаях, потому что если вы не собираетесь использовать его никогда в своем приложении, просто удалите его из своей модели.

Если вы хотите использовать его только в некоторых сценариях и избежать его "обнуления" в приведенном выше случае, вы можете попробовать:

  • скрыть параметр в представлении с помощью HiddenFor:

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

это сделает ваше исходное значение будет оставалось неизменным и передавалось обратно контроллеру.

загрузите снова свой объект в контроллер из вашего DBSet и запустите этот метод. Вы можете указать белый список и черный список параметров, которые должны или не должны обновить.

Я сделал простой способ редактирования свойств объектов я поделюсь с вами. этот код будет редактировать имя и семейство свойств сущности:

    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
}