Подтвердить что ты не робот

Исключить свойство для обновления в инфраструктуре Entity

Я искал подходящий способ отметить свойство, которое НЕ будет изменено при обновлении модели в 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();

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

4b9b3361

Ответ 1

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

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

он обновится, но без свойства Token

Ответ 2

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

т.е. если ваша модель объекта:

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

Вы можете создать пользовательскую модель представления, которая позволит пользователю изменять имя, но не флаг Enabled:

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 останется без изменений. Я использовал простые модели, но я думаю, вы получите изображение, как его использовать.

Ответ 3

Любой, кто ищет, как добиться этого на EF Core. Это в основном то же самое, но ваш IsModified должен быть после добавления модели для обновления.

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

Ответ 4

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

    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
}

Ответ 5

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

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

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

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

Это приведет к тому, что ваше исходное значение будет сохранено без изменений и передано обратно контроллеру.

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