我只是在学习 MVC 并结合实体框架处理它的无状态性质。我的问题是,有没有更优雅的方式来处理下面的场景?
我有两个 POCO 实体:
public class Contest
{
public long ID { get; set; }
.... .....
public ICollection<ContestPrize> Prizes { get; set; }
}
public class ContestPrize
{
public long ID { get; set; }
public Contest Contest { get; set; }
}
然后我有一个 MVC 视图,它显示了比赛和与之相关的所有奖品。在该视图中,我有一个“创建奖品”链接来创建一个新奖品,它将比赛的 ID 传递给 ContestPrize 控制器,如下所示:
@Html.ActionLink("Create Prize", "Create", "ContestPrizes", new { ContestId = Model.ID }, null)
ContestId 作为提交新奖品的表单中的隐藏字段保留,以便我可以在创建时检索它。奖品控制器上的创建方法如下:
[HttpPost]
public ActionResult Create(int ParentID, ContestPrize ContestPrize)
{
if (ModelState.IsValid)
{
db.ContestPrizes.Add(ContestPrize);
db.SaveChanges();
return RedirectToAction("Index", "Contests", ParentID);
}
return View(ContestPrize);
}
这就是我遇到一些我不喜欢的丑陋的地方。以下是问题:
- 测试
ModelState.IsValid
失败。这是因为父级的导航属性在模型上为空。它没有被填充。我可以跳过对模型的验证并直接进入数据库,但是有没有办法在不执行下面的 #2 的情况下填充它? - 此时未填充父属性,但我确实有来自隐藏表单字段的 ParentID。由于一切都是无状态的,因此 db 对象没有父对象(这很好)。因此,我可以执行另一个数据库读取以使用 parentID 获取父对象,然后执行
Parent.Prizes.Add(ContestPrize)
orContestPrize.Contest = Parent
。但我真的不喜欢这样,因为当我拥有创建子记录所需的所有信息时,我正在做一个额外的数据库访问来读取父级。
那么,Entity Framework 有没有办法只设置父对象的 ID 并保存子对象而无需检索父对象?或者...理想情况下,有没有办法使用 MVC 在创建时使用父对象预填充新模型,因为在进入创建视图之前我确实有父对象?在 ViewData 中传递父对象以使其可用会有多糟糕?
我可以通过重新加载父母来完成这项工作。但如果可能的话,我想避免它。
想法?
更新: 添加ContestID
到 ContestPrize POCO,然后[ForeignKey("ContestID")]
按照@NSGaga 的建议装饰导航属性完美地工作,并消除了一些混乱的 ParentID 传递问题。新的 POCO 如下所示:
public class Contest
{
public long ID { get; set; }
.... .....
public ICollection<ContestPrize> Prizes { get; set; }
}
public class ContestPrize
{
public long ID { get; set; }
public long ContestID { get; set; }
[ForeignKey("ContestID")]
public Contest Contest { get; set; }
}
我可以消除在视图中传递的 ParentID 并将其设置为隐藏字段,因为 MVC 中的数据绑定负责新实体上的 ContestID(我仍然必须将 id 传递到初始视图中,但仅此而已。它是刚从那里绑定)。Controller 上的新 Create 操作如下所示:
[HttpPost]
public ActionResult Create(ContestPrize ContestPrize)
{
if (ModelState.IsValid)
{
db.ContestPrizes.Add(ContestPrize);
db.SaveChanges();
return RedirectToAction("Index", "Contests", ContestPrize.ContestID);
}
return View(ContestPrize);
}
干净简单,没有乱七八糟的。我喜欢。