具有反向绑定的复选框

Checkbox with inverted binding

我有两个实体,CustomerUser,如下所示:

public class User
{
    [Key]
    public int Id { get; set; }
    [StringLength(20)]
    public string CustomerId { get; set; }
    public string Password { get; set; }
    public bool Locked { get; set; }
    [ForeignKey("CustomerId")]
    public virtual Customer Customer { get; set; }
}

public class Customer
{
    [Key]
    [Column("Id", TypeName = "nvarchar")]
    [StringLength(20)]
    public string Id { get; set; } // nvarchar(20)
    [Required]
    public string GivenName { get; set; } // nvarchar(100)
    [Required]
    public string Surname { get; set; } //  nvarchar(100)
    public virtual ICollection<User> Users { get; set; }
}

我有一个用于编辑客户的简单强类型视图,我想在视图中添加一个具有以下逻辑的复选框 - 当至少有一个用户时,应该选中该复选框客户和第一个用户的 Locked 属性 设置为 false。我只是找不到方法来完成这个。在 MVC 中执行此操作的正确方法是什么?以及处理方法([HttpPost]Edit)如何接收此复选框的值,目前它只是获取 Customer 对象?我应该为此视图创建一个额外的模型吗?还是有别的办法?
预料到这个问题我应该说我正在注意不会有超过一个客户的用户。

更新:

  1. 我已经为客户添加了一个视图模型并更新了编辑视图和控制器以使用该模型:

    public class CustomerViewModel
    {
      public Model.Data.Customer  BaseCustomer    { get; set; }
    
      public bool                 HasActiveUser   { get; set; }
    }
    

    我的编辑保存方法现在看起来像这样:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(ViewModel.Data.Customer customer)
    {
        if (ModelState.IsValid)
        {
            //db.Entry(customer.BaseCustomer).Collection("Users").Load();
            db.Entry(customer.BaseCustomer).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        ViewBag.CustomerTypeId = new SelectList(db.CustomerTypes, "Id", "Name", customer.BaseCustomer.CustomerTypeId);
        return View(customer);
    }
    

剩下的唯一问题是如何访问空的 Users 导航 属性,我尝试重新加载它,但得到的 InvalidOperationException 错误显示为 Member 'Load' cannot be called for property 'Users' because the entity of type 'Customer' does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet<Customer>. 我也曾尝试用 Customer baseCustomer = db.Customers.Find(customer.Id); 再次吸引客户,但后来我无法设置 db.Entry(customer.BaseCustomer).State = EntityState.Modified; 因为它告诉我 An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key. 有什么想法吗?

我决定继续创建一个专用的视图模型,它将包含域模型对象(如第二个模式 ASP.NET MVC View Model Patterns by Steve Michelotti 所建议的那样)和一个额外的 属性 用于绑定到我的复选框。然后在控制器中,我处理有关何时显示选中的复选框以及何时创建新用户(如果不存在)的所有逻辑。我遇到了几个问题,所以我想 post 我的解决方案,也许它们远非最佳实践,但我认为它们可能对初学者有用,我绝对希望看到评论或其他解决方案。

  1. 如果对象不参与视图,则对象不会持久化,因为 EF 在 post-back 从视图接收的数据中重新创建它们。这阻止了我添加一个 User 属性 ,它将成为 Customer 的导航集合 Users 属性 中第一个 User 的访问器(当我添加了它,它无法访问 Users,因为这个 属性 在 post-back 之后为 null,据我所知,这是因为重新创建的 Customer 与上下文分离).
  2. 为了能够使用导航属性,我必须通过设置 db.Entry(customer.BaseCustomer).State = EntityState.Modified;(感谢 Using DbContext in EF 4.1 Part 4: Add/Attach and Entity States § Attaching an existing but modified entity to the context) 并通过调用 db.Entry(customer.BaseCustomer).Collection("Users").Load();
  3. 重新加载集合