我们将 MVC 与实体框架结合使用。在某些时候,我们正试图在两个实体之间建立联系。这在单元测试中工作正常,但在从 MVC 控制器方法尝试时会出现以下错误:
“保存不为其关系公开外键属性的实体时发生错误。EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。“</p>
(精简)类:
public class Position : Entity
{
public string Function { get; set; }
public Organization Organization{ get; set; }
// public Guid? OrganizationId { get; set; }
// works when enabled!
}
public class Organization: Entity
{
public string Name { get; set; }
public IList<Position> Contacts
{
get {return contacts;}
set { contacts = value; }
}
public class EntityConfiguration :
EntityConfigurationBase<Organization>
{
public EntityConfiguration()
{
HasMany(p => p.Contacts)
.WithOptional(y => y.Organization)
}
}
private IList<Position> contacts = new List<Position>();
}
失败的(精简)控制器方法:
[HttpPost]
public ActionResult Edit(Position position, string organizationId = "")
{
if (!ModelState.IsValid)
{
return View(position);
}
db.Entry(position).State = EntityState.Modified;
if (!string.IsNullOrEmpty(organizationId))
{
Guid orgId = Guid.Parse(organizationId);
Organization organization =
db.Organizations
.First(x => x.Id.Equals(orgId));
position.Organization = organization;
}
db.SaveChanges();
RedirectToAction("Index");
}
通过的单元测试:
[TestMethod]
public void LinkOrganizationToPositionTest()
{
// arrange
DbModel dbModel;
Organization org;
Position pos;
Guid orgId;
using (dbModel = new DbModel())
{
dbModel.Database.Delete();
dbModel.Database.Create();
// - first organization
org = dbModel.Organizations.Create();
org.Name = "TestOrgFirst";
dbModel.Entry(org).State = EntityState.Added;
pos = dbModel.Positions.Create();
pos.Function = "TestFunc";
dbModel.Entry(pos).State = EntityState.Added;
// - link pos to first org
pos.Organization = org;
org = dbModel.Organizations.Create();
org.Name = "TestOrgSecond";
dbModel.Entry(org).State = EntityState.Added;
orgId = org.Id;
dbModel.SaveChanges();
}
// act
// - obtain "fresh" model
using (dbModel = new DbModel())
{
// - get second org
org = dbModel.Organizations.Find(orgId);
pos = dbModel.Positions.Find(pos.Id);
pos.Organization = org;
dbModel.SaveChanges();
}
// assert
using (dbModel = new DbModel())
{
Position actual =
dbModel.Positions
.Include("Organization")
.First(x => x.Id.Equals(pos.Id));
// - link was saved
Assert.AreEqual(
"TestOrgSecond",
actual.Organization.Name
);
}
}
为什么 MVC 需要 OrganizationId 外键属性?是否有一个不需要模型中所有外键的简单修复?