Я искал правильный способ отметить свойство, которое НЕ должно изменяться при обновлении модели в 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();
На данный момент лучший способ, который я нашел, - это включить все свойства и вручную задать все свойства, которые я хочу включить, но на самом деле я хочу только сказать, какие из них следует исключить.
c#
asp.net-mvc
entity-framework
Мануэль Швайгерт
источник
источник
using (var db2 = new DataContext()) model.Token = db2.Models.Find(model.Id).Token;
но и эта меня не устраивает.Ответы:
мы можем использовать вот так
db.Entry(model).State = EntityState.Modified; db.Entry(model).Property(x => x.Token).IsModified = false; db.SaveChanges();
он будет обновляться, но без свойства Token
источник
AddOrUpdate
? - Откуда вы знаете, что использоватьEntityState.Modified
илиEntityState.Added
?db.Entry(model).State = EntityState.Modified;
после настройкиdb.Entry(model).Property(x => x.Token).IsModified = false;
, свойство будет обновлено при сохранении.Создайте новую модель, которая будет иметь ограниченный набор свойств, которые вы хотите обновить.
Т.е. если ваша модель сущности:
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 останется без изменений. Я использовал простые модели, но думаю, вы поймете, как их использовать.
источник
Всем, кто ищет, как этого добиться в EF Core. Это в основном то же самое, но ваш IsModified должен быть после добавления модели для обновления.
db.Update(model); db.Entry(model).Property(x => x.Token).IsModified = false; db.SaveChanges();
источник
Я сделал простой способ редактировать свойства объектов, которыми поделюсь с вами. этот код будет редактировать свойства Name и Family объекта:
public void EditProfileInfo(ProfileInfo profileInfo) { using (var context = new TestContext()) { context.EditEntity(profileInfo, TypeOfEditEntityProperty.Take, nameof(profileInfo.Name), nameof(profileInfo.Family)); } }
И этот код будет игнорировать редактирование свойств Name и 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 }
источник
Я полагаю, вы не хотите, чтобы свойство изменялось только в некоторых случаях, потому что, если вы не собираетесь использовать его никогда в своем приложении, просто удалите его из своей модели.
Если вы хотите использовать его только в некоторых сценариях и избежать его «обнуления» в приведенном выше случае, вы можете попробовать:
Скрыть параметр в представлении с помощью HiddenFor:
@Html.HiddenFor(m => m.Token)
В результате исходное значение останется неизменным и будет передано контроллеру.
TryUpdateModel
: http://msdn.microsoft.com/en-us/library/dd460189(v=vs.108).aspxСнова загрузите ваш объект в контроллер из вашего
DBSet
и запустите этот метод. Вы можете указать как белый список, так и черный список параметров, которые должны или не должны обновляться.источник
@Html.HiddenFor
запишет значение в HTML-код представления и позволит пользователю использовать элемент inspect в своем браузере и изменять его. После этого он по-прежнему передается контроллеру, но с другим значением и будет обновлен. Я только что это проверил.