您从两个视图模型开始。第一个代表选定公司的...
public class CompanySelectViewModel
{
public int CompanyId { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
...以及要创建的订阅的第二个:
public class SubscriptionCreateViewModel
{
public int Amount { get; set; }
public IEnumerable<CompanySelectViewModel> Companies { get; set; }
}
然后在SubscriptionController
s GET 操作中,您从数据库中加载公司以初始化视图模型:
public ActionResult Create()
{
var viewModel = new SubscriptionCreateViewModel
{
Companies = _context.Companies
.Select(c => new CompanySelectViewModel
{
CompanyId = c.CompanyId,
Name = c.Name,
IsSelected = false
})
.ToList()
};
return View(viewModel);
}
现在,您有一个用于此操作的强类型视图:
@model SubscriptionCreateViewModel
@using (Html.BeginForm()) {
@Html.EditorFor(model => model.Amount)
@Html.EditorFor(model => model.Companies)
<input type="submit" value="Create" />
@Html.ActionLink("Cancel", "Index")
}
要正确呈现公司复选框,您需要引入一个编辑器模板。它必须具有名称CompanySelectViewModel.cshtml
并进入文件夹Views/Subscription/EditorTemplates
(如果不存在,则手动创建这样的文件夹)。这是一个强类型的局部视图:
@model CompanySelectViewModel
@Html.HiddenFor(model => model.CompanyId)
@Html.HiddenFor(model => model.Name)
@Html.LabelFor(model => model.IsSelected, Model.Name)
@Html.EditorFor(model => model.IsSelected)
Name
添加为隐藏字段以在 POST 期间保留名称。
显然,您必须对视图进行更多样式设置。
现在,您的 POST 操作将如下所示:
[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
var subscription = new Subscription
{
Amount = viewModel.Amount,
Companies = new List<Company>()
};
foreach (var selectedCompany
in viewModel.Companies.Where(c => c.IsSelected))
{
var company = new Company { CompanyId = selectedCompany.CompanyId };
_context.Companies.Attach(company);
subscription.Companies.Add(company);
}
_context.Subscriptions.Add(subscription);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
除了使用Attach
,您还可以先使用var company = _context.Companies.Find(selectedCompany.CompanyId);
. 但是Attach
您不需要往返数据库来加载要添加到集合中的公司。
(编辑 2:在这个答案Edit
中是具有相同示例模型的操作和视图的延续。)
编辑
您的模型并不是真正的多对多关系。相反,您有两个一对多的关系。PublicTransportSubscriptionByCompany
不需要实体 - 通常情况下。如果您在该表中有一个复合主键Id_PublicTransportSubscription, Id_PublicTransportCompany
并删除了 id 列Id_PublicTransportSubscriptionByCompanyId
EF 会将此表模式检测为多对多关系,并在每个实体中为订阅和公司创建一个集合,它不会创建任何实体对于链接表。我上面的代码将适用。
如果您出于某种原因不想更改架构,则必须更改 POST 操作,如下所示:
[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
var subscription = new Subscription
{
Amount = viewModel.Amount,
SubscriptionByCompanies = new List<SubscriptionByCompany>()
};
foreach (var selectedCompany
in viewModel.Companies.Where(c => c.IsSelected))
{
var company = new Company { CompanyId = selectedCompany.CompanyId };
_context.Companies.Attach(company);
var subscriptionByCompany = new SubscriptionByCompany
{
Company = company
};
subscription.SubscriptionByCompanies.Add(subscriptionByCompany);
}
_context.Subscriptions.Add(subscription);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}