EnitityFramework在模型中处理带有Collection
的多对多(*:*)。所以,我有一个SupportEvent
和Employee
表,每个表都有(*:*)关系和集合。我需要在Razor页面上添加员工参加支持活动。
最初,我是通过在表单中单独传递数据而以不那么优雅的方式进行的。调用Edit(SupportEvent)
方法时,对Employees
集合所做的更改已存在。但是,当我调用SaveChanges(supportEvent)
时,更改未持久保存到数据库。
环顾四周后,我发现ViewModel是正确处理这个问题的方法,所以我跟着MVC 5, Entity Framework 6 and Many to Many Relationship : a step by step View Model approach。
即时问题"我发现,尽管这种方式可能更符合模式,但当我输入Edit()
方法时,supportEvent
完全相同,SaveChanges()
的结果也是如此。除了名称和拼写错误之外,我无法以有意义的方式看到我的代码有所不同。
这是我的代码:
// ViewModel
public class SupportEventViewModel
{
public SupportEvent SupportEvent { get; set; }
public IEnumerable<SelectListItem> AllEmployees { get; set; }
private List<int> selectedEmployees;
public List<int> SelectedEmployees
{
get
{
if (selectedEmployees == null)
{
selectedEmployees = SupportEvent
.Employees
.Select(m => m.Id)
.ToList();
}
return selectedEmployees;
}
set { selectedEmployees = value; }
}
}
编辑():
// SupportEventController - Edit()
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SupportEventViewModel model, bool? active)
{
foreach(var e in model.SelectedEmployees)
{
model.SupportEvent.Employees
.Add(db.Employees.Find(e));
}
if (ModelState.IsValid)
{
db.Entry(model.SupportEvent).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction(((bool)active) ?
"ActiveTicketDetails" : "Details", "Ticket", new { id = model.SupportEvent.TicketId });
}
return View(model);
}
部分编辑视图:
// The partial view/form
@model ProjectWhiteWave.ViewModels.SupportEventViewModel
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SupportEvent</h4>
<hr />
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.SupportEvent.SupportEventId)
<div class="form-group">
@Html.LabelFor(model => model.SupportEvent.DateOpened, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.SupportEvent.DateOpened)
@Html.ValidationMessageFor(model => model.SupportEvent.DateOpened)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.SupportEvent.DateClosed, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.SupportEvent.DateClosed)
@Html.ValidationMessageFor(model => model.SupportEvent.DateClosed)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.AllEmployees, "Technicians", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.ListBoxFor(model => model.SelectedEmployees, Model.AllEmployees)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.SupportEvent.Description, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.SupportEvent.Description)
@Html.ValidationMessageFor(model => model.SupportEvent.Description)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</body>
</html>
一切似乎都是正确的,我认为我在视图中所做的更改最终会在编辑方法中得到验证。我知道它没有被保存,因为当Edit
重定向并且我返回到详细信息页面时,没有任何更改。
我遗漏/做错了什么阻止数据保存到数据库?
答案 0 :(得分:0)
我认为这一行:
model.SupportEvent.Employees.Add(db.Employees.Find(e));
应替换为此行:
model.SupportEvent.Employees.Add(db.Employees.Find(emp => emp.Id = e));
因为 e 实际上是特定员工的 id (即选择(m =&gt; m.Id)的含义在SelectedEmployees上)
答案 1 :(得分:0)
我认为你所说的是员工可以有多个支持活动,支持活动可以有多个员工?如果没有中间的联结表,则无法映射此关系。您需要告诉EF根据此关系创建联结表。
如果您已经完成了这个操作,那么只需忽略之前的语句,但请查看以下代码,了解我如何设置简单的多对多关系,看看是否有帮助。
public class Employee
{
[Key]
public Guid Id { get; set; }
public virtual ICollection<SupportEvent> SupportEvents { get; set; }
}
public class SupportEvent
{
[key]
public Guid Id { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
// DbContext
public DbSet<Employee> Employees { get; set; }
public DbSet<SupportEvent> SupportEvents { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasMany(x => x.SupportEvents)
.WithMany(x => x.Employees)
.Map(m =>
{
m.ToTable("EmployeeSupportEvents");
m.MapLeftKey("EmployeeId");
m.MapRightKey("SupportEventId");
}
}
现在添加或删除反之员工的事件非常容易。
var event = db.SupportEvents.FirstOrDefault(x => x.Id == "whatever");
var employee = db.Employee.FirstOrDefault(x => x.Id = "blah");
if(event == null || employee == null) return NotFound();
event.Employees.Add(employee);
// OR
employee.SupportEvents.Add(event);
db.SaveChanges();