这个问题与基本的linq构建块如何与实体框架进行交互有关。
采取以下(伪)代码:
IQueryable<Address> addresses;
Using (var db = new ObjectContext()) {
addresses = db.Users.Addresses.Where(addr => addr.Number > 1000);
}
addresses.Select(addr => Console.WriteLine(addr.City.Name));
这看起来不错,但会引发运行时错误,因为所谓的IQueryable的接口。
IQueryable implements IEnumerable并为表达式和提供者添加信息。这基本上允许它针对数据库构建和执行sql语句,而不必在获取数据和遍历它们时像载入IEnumerable一样加载整个表。
由于linq推迟表达式的执行直到它被使用,它将IQueryable表达式编译为SQL,并在需要之前执行数据库查询。这可以加快速度,并且每执行一次Where()
或Select()
时都不需要访问数据库,就可以进行表达式链接。副作用是如果对象在db的作用域之外使用,那么在db被处置之后执行sql语句。
要强制LINQ来执行,你可以使用ToList,像这样:
IQueryable<Address> addresses;
Using (var db = new ObjectContext()) {
addresses = db.Users.Addresses.Where(addr => addr.Number > 1000).ToList();
}
addresses.Select(addr => Console.WriteLine(addr.City.Name));
这将迫使LINQ执行对数据库的表达,并得到所有的地址与数千余更大。如果你需要访问地址表中的一个字段,这是非常好的,但是因为我们想要得到一个城市的名字(与你的关系类似的1..1),所以我们会在它能够运行之前再次遇到碰撞:延迟加载。
实体框架lazy loads实体默认情况下,所以没有任何东西从数据库中提取,直到需要。同样,这会大大加快速度,因为如果没有它,每次对数据库的调用都可能将整个数据库带入内存;但具有取决于可用上下文的问题。
您可以将EF设置为eager load(在您的模型中,转到属性并将'Lazy Loading Enabled'设置为False),但这会带来很多您可能不会使用的信息。
针对此问题最好的解决方法是执行里面的东西分贝的范围:
IQueryable<Address> addresses;
Using (var db = new ObjectContext()) {
addresses = db.Users.Addresses.Where(addr => addr.Number > 1000);
addresses.Select(addr => Console.WriteLine(addr.City.Name));
}
我知道这是一个非常简单的例子,但在现实世界中,你可以使用一个DI容器像ninject来处理你的依赖并在应用程序的执行过程中让您的数据库可用。
这给我们留下了Include。包括将IQueryable的包括所有指定的关系路径生成SQL语句时:
IQueryable<Address> addresses;
Using (var db = new ObjectContext()) {
addresses = db.Users.Addresses.Include("City").Where(addr => addr.Number > 1000).ToList;
}
addresses.Select(addr => Console.WriteLine(addr.City.Name));
这将工作,这是无需加载整个数据库,并具有重构整个项目以支持DI之间一个很好的折衷。
你可以做的另一件事是地图multiple tables to a single entity。在你的情况下,由于关系是1-0..1,你不应该有这样做的问题。
尝试'PriceSnapshotSummary snapshot = db.PriceSnapshotSummaries.FirstOrDefault(pss => pss.Id == snapshotId).Include(“ComponentQuotes.InstrumentQuote.DataInfo”);'你也可以发布失败的代码吗? –
@NicolásStraubValdivieso谢谢!那样做了。对Synax的小修正是PriceSnapshotSummary snapshot = db.PriceSnapshotSummaries.Include(“ComponentQuotes.InstrumentQuote.DataInfo”)。FirstOrDefault(pss => pss.Id == snapshotId);对于有兴趣的其他人。 –
因此,如果没有FK存在,那么在EF中永远不会加载en实体? –