0

我有一个用户实体类:实体框架 - 查看2断开实体更新

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配置门户网站(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 Users。
  4. 我从UserWCPModel加载数据到用户对象。
  5. 我设置修改时间(不重要)。
  6. 我调用db.SaveChanges()(这是SaveToDb的作用)。

目标完成! 没有第二个SELECT查询。 不保存与模型无关的数据。 没有为每个属性调用IsModified。 以前输入的数据超出了模型范围。

我调整它如此糟糕,我要在这里分享,并为一些意见希望:d

希望有人会觉得这有用:)

+0

它的工作原理,但只是因为你有意使DB和UI“不一致”,可以这么说,因为你在数据库中有* optional/nullable *列,但是*在UI中需要*属性。也许你想或需要,但我会称这是一个非常“特殊”的架构。 – Slauma

回答

1

如果您正在使用更新您的实体此方法需要非常小心; conciser如果你尝试在相同的上下文中更新同一个实体两次,会发生什么。 (破坏者:当你尝试附加一个已经连接的实体时,你会得到一个例外)

另外,我会建议你为所有查询添加.AsNoTracking()(见my blog post on AsNoTracking),以便直到你实际上执行更新。这也有助于避免将实体附加到您的上下文中。

我想这种方法对我来说似乎就像是踩在危险的地面上,除非你绝对需要使用这种方法来提高性能。在我看来,你会更好地从数据库中获取实体,并手动更新属性并保存它。这可能会为你长期解决头痛问题。