很抱歉这么长,但至少我觉得我得到的所有信息都能够理解并可能有所帮助?
我想使用预先加载来从我的数据库加载数据。
数据设置在五个表中,设置两个m:n关系级别。因此,有三个表包含数据(以层次结构的方式从上到下排序):
CREATE TABLE [dbo].[relations](
[relation_id] [bigint] NOT NULL
)
CREATE TABLE [dbo].[ways](
[way_id] [bigint] NOT NULL
)
CREATE TABLE [dbo].[nodes](
[node_id] [bigint] NOT NULL,
[latitude] [int] NOT NULL,
[longitude] [int] NOT NULL
)
前两个实际上只包含他们自己的ID(将此处不相关的其他数据挂钩)。
在这三个数据表之间是两个m:n表,带有排序提示:
CREATE TABLE [dbo].[relations_ways](
[relation_id] [bigint] NOT NULL,
[way_id] [bigint] NOT NULL,
[sequence_id] [smallint] NOT NULL
)
CREATE TABLE [dbo].[ways_nodes](
[way_id] [bigint] NOT NULL,
[node_id] [bigint] NOT NULL,
[sequence_id] [smallint] NOT NULL
)
这实际上是OpenStreetMap数据结构的一部分。我让实体框架从这个数据库中构建它的对象,它就像表一样设置类。 m:n表确实作为类存在。 (我在EF中理解你可以构建你的对象m:n关系而不需要明确的中间类 - 我应该尝试以这种方式改变对象模型吗?)
我想做的事情:我的切入点只是一个关系项目。
我认为最好首先加载中间m:n关系,然后在循环中迭代并急切加载最低的关系。我试着用以下方式做到这一点
IQueryable<relation> query = context.relations;
query = query.Where( ... ); // filters down to exactly one
query = query.Include(r => r.relation_members);
relation rel = query.SingleOrDefault();
只需一次访问数据库即可加载关系及所有1:n信息 - 好的,好的。但我注意到它只加载1:n表,而不是中间数据表“方式”。
如果我修改这样的行,这不会改变:
query = query.Include(r => r.relation_members.Select(rm => rm.way));
所以我不能在这里加载中间级别,似乎?
我根本无法工作的是急切地加载节点级别的数据。我尝试了以下方法:
foreach (relation_member rm in rel.relation_members) {
IQueryable<way_node> query = rm.way.way_nodes.AsQueryable();
query = query.Include(wn => wn.node);
query.Load();
}
这确实有效并且在每次迭代的一个语句中急切地加载中间级方式和way_node的所有1:n信息,但是不来自节点的信息(纬度/经度)。如果我访问其中一个值,我会触发另一个数据库之旅以加载一个节点对象。
这最后一次旅行是致命的,因为我想加载1个关系 - &gt;每种方式300种方式 - &gt; 2000个节点。所以最后我打算服务器1 + 300 + 300 * 2000 ......我认为是改进的空间。
但是怎么样?我无法用有效的语法和急切加载来写这个最后的语句。 不感兴趣;有没有办法在一次旅行中加载整个对象图,从一个关系开始?答案 0 :(得分:5)
在一次往返中加载整个图表将是:
IQueryable<relation> query = context.relations;
query = query.Where( ... ); // filters down to exactly one
query = query.Include(r => r.relation_members
.Select(rm => rm.way.way_nodes
.Select(wn => wn.node)));
relation rel = query.SingleOrDefault();
但是,由于您说Include
最多...Select(rm => rm.way)
不起作用,因此不太可行。 (如果它能够正常工作,由于生成的SQL的复杂性以及此查询将返回的数据和实体的数量,性能可能并不好笑。)
您应该进一步调查的第一件事是.Include(r => r.relation_members.Select(rm => rm.way))
无效,因为它似乎是正确的。您的模型和映射到数据库是否正确?
通过显式加载获取节点的循环应如下所示:
foreach (relation_member rm in rel.relation_members) {
context.Entry(rm).Reference(r => r.way).Query()
.Include(w => w.way_nodes.Select(wn => wn.node))
.Load();
}
答案 1 :(得分:1)
Include()
由于某种原因,当涉及排序/分组/加入时,有时会被忽略。
在大多数情况下,您可以将Include()重写为Select()
到匿名中介对象中:
<强>之前:强>
context.Invoices
.Include(invoice => invoice .Positions)
.ToList();
<强>后:强>
context.Invoices
.Select(invoice => new {invoice, invoice.Positions})
.AsEnumerable()
.Select(x => x.invoice)
.ToList();
这样查询永远不会丢失Include()信息。
答案 2 :(得分:0)
//get an associate book to an author
var datatable = _dataContext.Authors
.Where(x => authorids.Contains(x.AuthorId))
.SelectMany(x => x.Books)
.Distinct();