我一直在寻找这个问题的答案 2 天了。我什至不确定到底出了什么问题,但我想我可能已经查明了可能的罪魁祸首。
我的程序是一个数据库跟踪器/管理器,它将跟踪我公司的设备。用户可以查询、创建和编辑设备。现在,查询数据库是可行的,但是当我尝试添加或更新数据库时,程序会抛出验证错误(我将在下面详细介绍)。
我有一个设备类,它有许多可以为空的属性(因为用户在创建新条目时可能不知道其中的许多属性,我们几乎所有属性都可以为空)并连接到(使用外键和延迟加载/“虚拟” ) 用于帮助规范化数据库的其他一些表。
以下是一些帮助的缩写代码:
设备型号:
public class Equipment
{
public int EquipmentId { get; set; } //required
public string Company { get; set; } //required
public bool Verified { get; set; } //required
(...other non-required attributes...)
//The following two attributes are where my problems are I believe
[ForeignKey("PAU")]
public int PAUId { get; set; } //required and Foreign Key
//This is not required (but is FK to the related table) if the user doesn't know
[ForeignKey("Division")]
public Nullable<int> DivisionId { get; set; }
//These are the lazy loading connections to the other tables in the database
public virtual Division Division { get; set; }
public virtual PAU PAU { get; set; }
}
部门型号:本表仅包含我公司5个不同部门及相关ID。
public class Division
{
public Division()
{
this.Equipments = new HashSet<Equipment>();
}
//These are non-nullable/required fields
public int DivisionId { get; set; }
public string DivisionName { get; set; }
public virtual ICollection<Equipment> Equipments { get; set; }
}
PAU 模型:此模型包含 PAU#s 以及相关的描述和 ID。
public class PAU
{
public PAU()
{
this.Equipments = new HashSet<Equipment>();
}
//These are non-nullable/required fields
public int PAUId { get; set; }
public string PAUNumber { get; set; }
public string PAUDescription { get; set; }
public virtual ICollection<Equipment> Equipments { get; set; }
}
设备控制器:
public class EquipmentController : Controller
{
TLCP_DEVEntities4 db = new TLCP_DEVEntities4();
(...)
public ActionResult Edit(int id)
{
ViewData["divisions"] = new SelectList(db.Equipments.
OrderBy(x => x.Division.DivisionName).
Select(x => x.Division).ToList().
Distinct(), "DivisionId", "DivisionName");
ViewData["PAUNumbers"] = new SelectList(db.Equipments.
OrderBy(x => x.PAU.PAUNumber).
Select(x => x.PAU).ToList().
Distinct(), "PAUId", "PAUNumber");
return View(db.Equipments.Find(id));
}
[HttpPost]
public ActionResult Edit(Equipment equipment)
{
if (ModelState.IsValid)
{
db.Entry(equipment).State = EntityState.Modified;
db.SaveChanges(); //fails here
return RedirectToAction("Maintenance");
}
ViewData["divisions"] = new SelectList(db.Equipments.
OrderBy(x => x.Division.DivisionName).
Select(x => x.Division).ToList().
Distinct(), "DivisionId", "DivisionName");
ViewData["PAUNumbers"] = new SelectList(db.Equipments.
OrderBy(x => x.PAU.PAUNumber).
Select(x => x.PAU).ToList().
Distinct(), "PAUId", "PAUNumber");
return View(equipment);
}
public ActionResult AddEquipment()
{
ViewData["divisions"] = new SelectList(db.Equipments.
OrderBy(x => x.Division.DivisionName).
Select(x => x.Division).ToList().
Distinct(), "DivisionId", "DivisionName");
ViewData["PAUNumbers"] = new SelectList(db.Equipments.
OrderBy(x => x.PAU.PAUNumber).
Select(x => x.PAU).ToList().
Distinct(), "PAUId", "PAUNumber");
return View();
}
public ActionResult AddEquipment(Equipment equipment)
{
try
{
db.Equipments.Add(equipment);
db.SaveChanges();
return RedirectToAction("Maintenance");
}
catch (Exception ex)
{
ViewData["divisions"] = new SelectList(db.Equipments.
OrderBy(x => x.Division.DivisionName).
Select(x => x.Division).ToList().
Distinct(), "DivisionId", "DivisionName");
ViewData["PAUNumbers"] = new SelectList(db.Equipments.
OrderBy(x => x.PAU.PAUNumber).
Select(x => x.PAU).ToList().
Distinct(), "PAUId", "PAUNumber");
return View();
}
}
(...)
}
在视图中,我有这些属性的下拉列表,这些属性填充了数据库中已有的可能选项(存储在上面的 ViewData 中)。我尝试了几种不同的方式将这些数据存储到我的模型中,但这种方式似乎效果最好:
<%: Html.DropDownListFor(model => model.DivisionId,
ViewData["divisions"] as SelectList, "")%>
好的,经过大量调试,问题似乎是因为延迟加载的属性具有空属性,这些属性在它们的表中是不允许的。我的示例将更多地处理创建新设备对象,尽管我相信编辑它们的问题是相同的。
Division 示例:因此 Equipment 类中的 DivisionId 可以为 null (用户不知道或设备不属于特定部门), Equipment 表/类不会抱怨这一点。但是当我尝试 SaveChanges() 时,程序会抱怨,因为虚拟 Division 对象为空(默认 DivisionId 为 0,DivisionName 为空)。由于 Equipment.DivisionId 为空,我不想更新此 Equipment 对象的 Division 表。有没有办法解决这个问题?我不应该延迟加载吗?
PAU 示例:由于 PAUId 是所有设备对象的必需属性,但与除法示例中一样,PAU.PAUNumber 和 PAU.PAUDescription 为空(并且 PAU.PAUId 为默认值 0)导致错误。这就像第一个一样,但具有 required 属性(所以我不确定它是否需要以不同方式处理)。
所以我不确定如何解决这个问题。
是否延迟加载问题,因为如果 Id/外键不为空,我只想将设备对象连接到其他表?
我可以调用一些方法来根据 Id 从其他表中更新设备对象的值吗?这是我需要自己创建的方法吗?
如果我摆脱延迟加载,您能解释一下我应该如何编写查询,以便我仍然可以访问规范化数据(如 DivisionName)吗?
我为超长的帖子道歉。我只是不想错过任何可能重要的事情。
编辑
我对 PAU 示例有一个粗略的解决方案(但我认为它不适用于除法示例,因为在设备中允许空值但不允许在单个表中使用空值)。
public ActionResult AddEquipment(Equipment equipment)
{
try
{
equipment.PAU.PAUId = equipment.PAUId;
equipment.PAU.PAUNumber = db.PAUs.Find(equipment.PAUId).PAUNumber;
equipment.PAU.PAUDescription = db.PAUs.Find(equipment.PAUId).PAUDescription;
(...)
}
虽然它不是很优雅。我试着看一个关于反射的教程,但它并没有真正的意义。如果那将是一个更优雅的解决方案,有人可以尝试解释一下吗?
我仍在寻找除法示例的解决方案(因为 Equipment.DivisionId 可以为空,但 Division.DivisionId 不能为空,这不起作用),因此任何关于此或更优雅的解决方案的帮助都会很大赞赏!