实体框架 - 渴望加载两个多对多关系

Ral*_*alf 5 linq-to-entities many-to-many entity-framework eager

对不起这么久,但至少我认为我得到的所有信息都能够理解并可能有所帮助?

我想使用急切加载从我的数据库加载数据.

数据设置在五个表中,设置两个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
)
Run Code Online (Sandbox Code Playgroud)

前两个实际上只包含他们自己的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
)
Run Code Online (Sandbox Code Playgroud)

这基本上是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();
Run Code Online (Sandbox Code Playgroud)

只需一次访问数据库即可加载关系和所有1:n信息 - 好的,好的.但我注意到它只加载1:n表,而不是中间数据表"方式".

如果我修改这样的行,这不会改变:

query = query.Include(r => r.relation_members.Select(rm => rm.way));
Run Code Online (Sandbox Code Playgroud)

所以我不能在这里加载中级,看来呢?

我根本无法工作的是急切地加载数据的节点级别.我尝试了以下方法:

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();
}
Run Code Online (Sandbox Code Playgroud)

这确实有效并且急切地在每个迭代的一个语句中加载中间级方式和way_node的所有1:n信息,但不是来自节点的信息(纬度/经度).如果我访问其中一个值,我会触发另一个数据库之旅以加载一个节点对象.

这最后一次旅行是致命的,因为我想加载1个关系 - > 300路,每路 - > 2000个节点.所以最后我打算服务器1 + 300 + 300*2000 ...我想改进的空间.

但是怎么样?我无法用有效的语法和急切加载来写这个最后的语句.不感兴趣; 有没有办法在一次旅行中加载整个对象图,从一个关系开始?

Sla*_*uma 6

在一次往返中加载整个图表将是:

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();
Run Code Online (Sandbox Code Playgroud)

不过,既然你说,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();
}
Run Code Online (Sandbox Code Playgroud)