Szukałem właściwego sposobu, aby oznaczyć właściwość jako NIE zmienianą podczas aktualizacji modelu w MVC.
Na przykład weźmy ten mały model:
class Model
{
[Key]
public Guid Id {get; set;}
public Guid Token {get; set;}
//... lots of properties here ...
}
wówczas metoda edycji utworzona przez MVC wygląda następująco:
[HttpPost]
public ActionResult Edit(Model model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
teraz, jeśli mój widok nie zawiera tokenu, zostanie on unieważniony przez tę edycję.
Szukam czegoś takiego:
db.Entry(model).State = EntityState.Modified;
db.Entry(model).Property(x => x.Token).State = PropertyState.Unmodified;
db.SaveChanges();
Jak dotąd najlepszym sposobem jest uwzględnienie wszystkich właściwości, które chcę uwzględnić, ręcznie, ale tak naprawdę chcę tylko powiedzieć, które z nich mają być wykluczone.
c#
asp.net-mvc
entity-framework
Manuel Schweigert
źródło
źródło
using (var db2 = new DataContext()) model.Token = db2.Models.Find(model.Id).Token;
Ale ja też nie jestem z tego zadowolony.Odpowiedzi:
możemy użyć w ten sposób
db.Entry(model).State = EntityState.Modified; db.Entry(model).Property(x => x.Token).IsModified = false; db.SaveChanges();
zaktualizuje się, ale bez właściwości tokena
źródło
AddOrUpdate
? - Skąd wiesz, jak używaćEntityState.Modified
lubEntityState.Added
?db.Entry(model).State = EntityState.Modified;
po ustawieniudb.Entry(model).Property(x => x.Token).IsModified = false;
, właściwość zostanie zaktualizowana przy zapisywaniu.Utwórz nowy model, który będzie miał ograniczony zestaw właściwości, które chcesz zaktualizować.
To znaczy, jeśli model Twojej jednostki to:
public class User { public int Id {get;set;} public string Name {get;set;} public bool Enabled {get;set;} }
Możesz utworzyć niestandardowy model widoku, który pozwoli użytkownikowi zmienić nazwę, ale nie opcję Włączono:
public class UserProfileModel { public int Id {get;set;} public string Name {get;set;} }
Jeśli chcesz zaktualizować bazę danych, wykonaj następujące czynności:
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(); } }
Wywołanie tej metody spowoduje zaktualizowanie nazwy, ale właściwość Enabled pozostanie niezmieniona. Użyłem prostych modeli, ale myślę, że zrozumiesz, jak go używać.
źródło
Każdy, kto szuka sposobu na osiągnięcie tego w EF Core. Zasadniczo jest tak samo, ale IsModified musi być po dodaniu modelu do aktualizacji.
db.Update(model); db.Entry(model).Property(x => x.Token).IsModified = false; db.SaveChanges();
źródło
Stworzyłem łatwy sposób na edycję właściwości podmiotów, którymi się z Tobą podzielę. ten kod będzie edytować właściwości nazwy i rodziny podmiotu:
public void EditProfileInfo(ProfileInfo profileInfo) { using (var context = new TestContext()) { context.EditEntity(profileInfo, TypeOfEditEntityProperty.Take, nameof(profileInfo.Name), nameof(profileInfo.Family)); } }
A ten kod zignoruje, aby edytować właściwości nazwy i rodziny jednostki i będzie edytować inne właściwości:
public void EditProfileInfo(ProfileInfo profileInfo) { using (var context = new TestContext()) { context.EditEntity(profileInfo, TypeOfEditEntityProperty.Ignore, nameof(profileInfo.Name), nameof(profileInfo.Family)); } }
Użyj tego rozszerzenia:
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 }
źródło
Myślę, że nie chcesz, aby ta właściwość była zmieniana tylko w niektórych przypadkach, ponieważ jeśli nie zamierzasz jej nigdy używać w swojej aplikacji, po prostu usuń ją z modelu.
Jeśli chcesz go użyć tylko w niektórych scenariuszach i uniknąć jego „unieważnienia” w powyższym przypadku, możesz spróbować:
Ukryj parametr w widoku za pomocą HiddenFor:
@Html.HiddenFor(m => m.Token)
Dzięki temu oryginalna wartość pozostanie niezmieniona i zostanie przekazana z powrotem do kontrolera.
TryUpdateModel
: http://msdn.microsoft.com/en-us/library/dd460189(v=vs.108).aspxZaładuj ponownie swój obiekt do kontrolera ze swojego
DBSet
i uruchom tę metodę. Możesz określić zarówno białą listę, jak i czarną listę parametrów, które mają być aktualizowane lub nie.źródło
@Html.HiddenFor
zapisze wartość w kodzie HTML widoku i umożliwi użytkownikowi użycie elementu inspect w przeglądarce i zmodyfikowanie go. Po wykonaniu tej czynności jest nadal przekazywana do kontrolera, ale z inną wartością i zostanie zaktualizowana. Właśnie to przetestowałem.