C# MVC 4编辑控制器/查看多对多关系和复选框
我正在使用ASP.NET MVC 4和实体框架,我正在寻找某种方法,从数据库中创建多对多关系和复选框,以创建/编辑控制器和视图,我在中找到了@Slauma answer for Create的答案,但是,我真的很想看看它是如何扩展到编辑和删除功能的,就像这个解决方案中的一些其他合作伙伴一样。有人能告诉我如何在编辑控制器方法中填充ClassificationSelectViewModel以获得“选中”和“未选中”值吗?这是一个Matt Flowers的问题,也将解决我的问题。以下是描述实体C# MVC 4编辑控制器/查看多对多关系和复选框,c#,entity-framework,asp.net-mvc-4,checkbox,many-to-many,C#,Entity Framework,Asp.net Mvc 4,Checkbox,Many To Many,我正在使用ASP.NET MVC 4和实体框架,我正在寻找某种方法,从数据库中创建多对多关系和复选框,以创建/编辑控制器和视图,我在中找到了@Slauma answer for Create的答案,但是,我真的很想看看它是如何扩展到编辑和删除功能的,就像这个解决方案中的一些其他合作伙伴一样。有人能告诉我如何在编辑控制器方法中填充ClassificationSelectViewModel以获得“选中”和“未选中”值吗?这是一个Matt Flowers的问题,也将解决我的问题。以下是描述实体订阅和公
订阅和公司之间具有多对多关系的模型的创建获取和发布操作的延续。
以下是编辑操作的步骤(除了我可能不会将所有EF代码放入控制器操作中,而是将其提取到扩展和服务方法中):
公司选择视图模型保持不变:
public class CompanySelectViewModel
{
public int CompanyId { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
@model CompanySelectViewModel
@Html.HiddenFor(model => model.CompanyId)
@Html.HiddenFor(model => model.Name)
@Html.LabelFor(model => model.IsSelected, Model.Name)
@Html.EditorFor(model => model.IsSelected)
SubscriptionEditViewModel
是SubscriptionCreateViewModel
加上Subscription
的关键属性:
public class SubscriptionEditViewModel
{
public int Id { get; set; }
public int Amount { get; set; }
public IEnumerable<CompanySelectViewModel> Companies { get; set; }
}
编辑
视图是创建
视图,以及订阅
的密钥属性Id
的隐藏字段:
@model SubscriptionEditViewModel
@using (Html.BeginForm()) {
@Html.HiddenFor(model => model.Id)
@Html.EditorFor(model => model.Amount)
@Html.EditorFor(model => model.Companies)
<input type="submit" value="Save changes" />
@Html.ActionLink("Cancel", "Index")
}
事后行动可能是这样的:
public ActionResult Edit(int id)
{
// Load the subscription with the requested id from the DB
// together with its current related companies (only their Ids)
var data = _context.Subscriptions
.Where(s => s.SubscriptionId == id)
.Select(s => new
{
ViewModel = new SubscriptionEditViewModel
{
Id = s.SubscriptionId
Amount = s.Amount
},
CompanyIds = s.Companies.Select(c => c.CompanyId)
})
.SingleOrDefault();
if (data == null)
return HttpNotFound();
// Load all companies from the DB
data.ViewModel.Companies = _context.Companies
.Select(c => new CompanySelectViewModel
{
CompanyId = c.CompanyId,
Name = c.Name
})
.ToList();
// Set IsSelected flag: true (= checkbox checked) if the company
// is already related with the subscription; false, if not
foreach (var c in data.ViewModel.Companies)
c.IsSelected = data.CompanyIds.Contains(c.CompanyId);
return View(data.ViewModel);
}
[HttpPost]
public ActionResult Edit(SubscriptionEditViewModel viewModel)
{
if (ModelState.IsValid)
{
var subscription = _context.Subscriptions.Include(s => s.Companies)
.SingleOrDefault(s => s.SubscriptionId == viewModel.Id);
if (subscription != null)
{
// Update scalar properties like "Amount"
subscription.Amount = viewModel.Amount;
// or more generic for multiple scalar properties
// _context.Entry(subscription).CurrentValues.SetValues(viewModel);
// But this will work only if you use the same key property name
// in ViewModel and entity
foreach (var company in viewModel.Companies)
{
if (company.IsSelected)
{
if (!subscription.Companies.Any(
c => c.CompanyId == company.CompanyId))
{
// if company is selected but not yet
// related in DB, add relationship
var addedCompany = new Company
{ CompanyId = company.CompanyId };
_context.Companies.Attach(addedCompany);
subscription.Companies.Add(addedCompany);
}
}
else
{
var removedCompany = subscription.Companies
.SingleOrDefault(c => c.CompanyId == company.CompanyId);
if (removedCompany != null)
// if company is not selected but currently
// related in DB, remove relationship
subscription.Companies.Remove(removedCompany);
}
}
_context.SaveChanges();
}
return RedirectToAction("Index");
}
return View(viewModel);
}
Delete
操作难度较小。在GET
操作中,您可以加载一些订阅属性以显示在删除确认视图上:
public ActionResult Delete(int id)
{
// Load subscription with given id from DB
// and populate a `SubscriptionDeleteViewModel`.
// It does not need to contain the related companies
return View(viewModel);
}
在POST
操作中,加载实体并将其删除。不需要包括公司,因为在多对多关系中(通常)启用了链接表上的级联删除,因此数据库将负责删除链接条目以及父订阅
:
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirm(int id)
{
var subscription = _context.Subscriptions.Find(id);
if (subscription != null)
_context.Subscriptions.Remove(subscription);
return RedirectToAction("Index");
}
杰克:基本上是从链接中创建模型/视图/控制器模式,除了一些小的例外,我需要的是编辑方法,我想我不能添加任何你在那里看不到的东西。谢谢你的另一个好答案!不过我不得不做一些小的更改。我必须更改data.ViewModel.Companies、 ForEach(c=>{c.IsSelected=data.CompanyId.Contains(c.CompanyId);});to ForEach(data.ViewModel.companys中的var c){c.IsSelected=data.CompanyId.Contains(c.CompanyId);}(很抱歉,注释格式不正确。)@Slauma嘿,这是一个愚蠢的问题,代码在视图上看起来像什么(使用复选框…+1非常有用我的意思是,在我的视图中使用CompanySelectViewModel
时,我得到**Error**传递到字典中的模型项类型为,因为它需要SubscriptionEditViewModel
@DonThomasBoyle:复选框是@Html.EditorFor(model=>model.IsSelected)
。CompanySelectViewModel
是编辑器模板的模型,而不是普通视图的模型。在另一篇关于创建的文章中有更详细的描述(请参阅我回答的第一行中的链接)@Slauma我必须用列表来修复复选框,而不是这里解释的Ienumerable
类型@DonThomasBoyle:是的,如果你使用Chris Pratt答案中的appoach,你必须使用列表,因为他用foreach循环直接在主视图中呈现复选框。我的方法是使用编辑器模板。引用另一个答案的话:“它必须有CompanySelectViewModel.cshtml的名称,并进入文件夹Views/Subscription/EditorTemplates(如果它不存在,则手动创建这样一个文件夹)”。在这种情况下,您可以使用IEnumerable
,只使用EditorFor(model=>model.companys)
,而不使用foreach循环。