0

У меня есть класс сущностей Пользователь:Entity Framework - Просмотр 2 отсоединен Entity обновление

public class User 
{ 
    [Key] 
    public int UserId { get; set; } 
    public string Username { get; set; } 
    public string Password { get; set; } 
    public string SecretQuestion { get; set; } 
    public string SecretAnswer { get; set; } 
    public string FullName { get; set; } 
    public string Email { get; set; } 
    public string Phone { get; set; } 
    public Nullable<byte> UserType { get; set; } 
    public Nullable<bool> Enabled { get; set; } 
    public Nullable<DateTime> Created { get; set; } 
    public Nullable<DateTime> Modified { get; set; } 

    public void LoadWCPModel(UserWCPModel model) 
    { 
     Username = model.Username; 
     Password = model.Password; 
     SecretQuestion = model.SecretQuestion; 
     SecretAnswer = model.SecretAnswer; 
     UserType = model.UserType; 
     Enabled = model.Enabled; 
    } 
} 

У меня есть класс модели для моего Web Portal Configuration (WCP):

public class UserWCPModel 
{ 
    [Key] 
    public int UserId { get; set; } 

    [Display(Name = "Username")] 
    [Required] 
    public string Username { get; set; } 

    [Display(Name = "Password")] 
    [Required] 
    public string Password { get; set; } 

    [Display(Name = "Secret question")] 
    [Required] 
    public string SecretQuestion { get; set; } 

    [Display(Name = "Secret answer")] 
    [Required] 
    public string SecretAnswer { get; set; } 

    [Display(Name = "User type")] 
    [Required] 
    public Nullable<byte> UserType { get; set; } 

    [Display(Name = "Enabled")] 
    [Required] 
    public Nullable<bool> Enabled { get; set; } 

    [ScaffoldColumn(false)] 
    public Nullable<DateTime> Created { get; set; } 

    [ScaffoldColumn(false)] 
    public Nullable<DateTime> Modified { get; set; } 

    /// Parameterless constructor for MVC model binder. 
    public UserWCPModel() 
    { 
     Created = DateTime.UtcNow; 
    } 

} 

Цель: Получить UserWCPModel и сохранять ТОЛЬКО данные из этой модели, не нанося вреда данным, заполненным другими приложениями (электронная почта, телефон, полное имя), а также полностью избегая перезагрузки данных из базы данных.

Во-первых, HttpPost Редактировать действие:

[HttpPost] 
    public ActionResult Edit(UserWCPModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      WrappedE result; 
      repo.Update(model, out result); 
      if (result.ErrorCode != ErrorCodes.Success) 
      { 
       /// Add error handling; 
      } 
      return RedirectToAction("Index"); 
     } 
     return View(model); 
    } 

Как вы можете видеть, я только вызвать метод Update из репозитория, пропусканием UserWCPModel.

Теперь вот метод репозитория:

public void Update(UserWCPModel model, out WrappedE result) 
    { 
     User user = new User();   
     user.UserId = model.UserId;   
     db.Users.Attach(user); 
     user.LoadWCPModel(model); 
     user.Modified = DateTime.UtcNow; 
     SaveToDb(out result); 
    } 
  1. Я построить пустой объект пользователя.
  2. Я присваиваю ему ID, взятый из модели.
  3. Я прикрепляю его к пользователям DbSet.
  4. Я загружаю данные из объекта UserWCPModel в объект User.
  5. Я установил измененное время (не важно).
  6. Я вызываю db.SaveChanges() (это то, что делает SaveToDb).

Цель достигнута! Нет второго запроса SELECT. Нет данных экономии, не связанных с моделью. Отсутствие вызова IsModified для каждого свойства. Отсутствие вреда ранее введенным данным, выходящим за рамки модели.

я подправил его так сильно, что я должен поделиться этим здесь, и надеюсь на некоторые комментарии: D

Надежда кто-то найдет это полезное :)

+0

Это работает, но только потому, что вы делаете DB и UI намеренно «непоследовательными», так сказать, поскольку у вас есть * необязательные/нулевые столбцы в базе данных, но * обязательные * свойства в пользовательском интерфейсе. Возможно, вам это нужно или нужно, но я бы назвал это очень «специальной» архитектурой. – Slauma

ответ

1

Если вы используете этот метод для обновления объектов Вы нужно быть очень осторожным; что произойдет, если вы попытаетесь дважды обновить один и тот же объект в одном контексте. (Спойлер: вы получите исключение при попытке прикрепить объект, который уже прилагается)

Кроме того я бы рекомендовал добавить .AsNoTracking() (см my blog post on AsNoTracking) на все вопросы, так что вы действуете на чтение только лиц, вплоть до вы действительно выполняете обновление. Это также поможет избежать двойного прикрепления объектов к вашему контексту.

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

Смежные вопросы