虽然我喜欢我正在学习的东西,但我觉得这很困难,需要一些帮助
我一直在使用这两个教程,我觉得很棒: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx http://msdn.microsoft.com/en-us/data/gg685467
目前我的主要问题/困惑是:
我有一个CodeFirst表/实体我不知道如何正确地从其他表/实体中获取数据以显示在我的视图中:
public class Car {
public int ID { get; set; }
public string Name { get; set; }
public int EngineID { get; set; }
public virtual Engine { get; set; }
}
public class Engine {
public int ID { get; set; }
public string Name { get; set; }
public string Manufacturer { get; set; }
// (plus a whole lot of other things)
}
现在当我创建一个汽车视图(使用列表类型/选项)时,我得到了一个很好的自动生成列表
@foreach (var item in Model) {
<tr>
<td>@item.ID</td>
<td>@item.Name</td>
<td>@item.EngineID</td>
</tr>
完美...除了EngineID对观众来说几乎毫无价值,我想要显示Engine.Name
所以我假设我可以使用EF延迟加载:
<td>@item.Engine.Name</td>
不幸的是,当我尝试这样做时,它说我的ObjectContext已被处理掉,因此无法获得需要连接的任何其他数据
然后我尝试去控制器并包含Engine.Name
var cars = (from c in db.Cars.Include("Engine.Name") select c;
告诉我:Entities.Engine没有声明一个名为'Name'的导航属性
......?在于
包含(“引擎”)工作正常,但我想要的只是名称,而包含(“引擎”)正在加载大量我不想要的东西
以前在这样的情况下,我在DB for Car中创建了一个包含EngineName的视图。但是使用CodeFirst和我的noobness我还没有办法做到这一点
我该如何解决这个问题?
我想也许我可以创建一个与Car实体完全相同的模型,但是将Engine.Name添加到它。这很好,因为我可以在多个地方重复使用它,但我不知道如何填充它等等
想要学习TDD,但上述内容已让我感到沮丧:p
Ps任何其他教程链接或方便阅读的内容将不胜感激
答案 0 :(得分:2)
这并不是谎言,因为你实际上试图包含一个属于第二级的属性而不给它一种导航方式。如果你让EF使用这种结构生成你的数据库,它可能会创建一个名为Car_Engine的导航表,如果你包含没有它映射的对象的名称,那么它在你的新对象中没有导航属性。
解决这个问题的简单方法是:
(from c in db.Cars.Include("Engine") select new { c, EngineName = c.Engine.Name }
如果仍然出现导航属性错误,则可能需要确保正确映射到架构。这可以使用流畅的API使用EntityTypeConfiguration类完成 - 非常强大。
这当然无助于强力输入您的汽车对象以在MVC中显示。 如果你想绕过这个,你的直觉是正确的。使用只读(通过设计,不一定设置为只读)的视图模型是很常见的,这些类提供了简单的数据视图。
我个人保持我的模型非常干净,然后有另一个项目与视图模型和一个演示项目填充。我会避免在核心模型中使用重叠实体,因为它可能会导致数据上下文中出现不可预测的行为,并且在更新多个实体(即负责更新引擎名称的人员?)时至少会出现持久性的噩梦。
使用viewmodels,您可以拥有一个名为CarSummaryView的类或只包含您想要的数据的类。这也解决了在您的网站上容易过度叠加或过度使用的问题。它可以很容易地填充上面的查询。
PS除了不加载完整的heirarchies之外,使用视图模型还有很多优点。其中一个最大的好处就是它可以避免过度和不足的情况。
有很多方法可以实现视图模型,但作为一个简单的CarView示例:
public class CarView
{
public int ID { get; set; }
public string Name { get; set; }
public string EngineName { get; set; }
}
这应该与您的实体模型明确分开。在一个大型项目中,您将拥有一个可以返回的单个viewmodels项目,但是在较小的项目中,您只需要与服务代码位于同一层中。
要直接从查询中填充它,您可以执行以下操作
List<CarView> cars = (from c in db.Cars.Include("Engine.Name") select new CarView() { ID = c.ID, Name = c.Name, EngineName = c.Engine.Name }).ToList();