如何以N:N关系手动加载相关实体?

Álv*_*cía 5 c# many-to-many entity-framework-5

我正在使用EF5,当关系为1:N时,如果我想加载相关实体,我会执行以下操作:

此时,EF使用相关实体填充主要实体的属性导航.另外,在每个实体的类型的本地属性中,dbContext我拥有每种类型的所有实体.

但是,如果我使用N:N关系做同样的事情,我没有关系中间表的实体,当我执行查询时,我在dbContext每个类型的实体的本地执行,但是未填充属性导航.

我想知道为什么以及它是否存在替代方案.

我使用这种方式是因为我想使用T-SQL来创建动态查询.如果我使用预先加载,那么动态查询的灵活性与使用TSQL时不同,效率较低.如果我使用显式加载我做N个额外的查询,主要实体的结果中的每个记录之一用我的方式,我只有一个额外的查询,因为我一次得到所有相关的实体.如果我使用延迟加载我有同样的问题,N个额外的查询.

当关系为N:N时,为什么EF不会填充相关属性?

谢谢.

Sla*_*uma 9

您正在谈论的功能称为关系跨度关系修复,实际上 - 正如您所注意到的 - 它不适用于多对多关系.它只有在关联的至少一端具有多重性1(或0..1)时才有效,即它适用于一对多或一对一的关系.

关系Span依赖于具有外键的实体.如果它具有显式外键属性(外键关联)或仅具有相应数据库表中的外键列而没有模型中的属性(独立关联)则无关紧要.在这两种情况下,当实体加载时,FK值将被加载到上下文中.基于此外键值,EF能够确定与此FK值具有相同主键值的相关实体是否附加到上下文,如果是,则可以"修复关系",即它可以填充导航属性正确.

现在,在多对多关系中,两个相关实体都没有外键.外键存储在此关系的链接表中,并且 - 如您所知 - 链接表没有相应的模型实体.因此,永远不会加载外键,因此上下文无法确定哪些附加实体是相关的,并且无法修复多对多关系并填充导航集合.

EF将支持您在多对多关系中使用填充的导航集合构建正确的对象图形的唯一LINQ查询是急切的加载......

var user = context.Users.Include(u => u.Roles).First();
Run Code Online (Sandbox Code Playgroud)

......或者懒加载......

var user = context.Users.First();
var rolesCount = user.Roles.Count();
// Calling Count() or any other method on the Roles collection will fill
// user.Roles via lazy loading (if lazy loading is enabled of course)
Run Code Online (Sandbox Code Playgroud)

...或直接将结果分配给导航集合的显式加载:

var user = context.Users.First();
user.Roles = context.Entry(user).Collection(u => u.Roles).Query().ToList();
Run Code Online (Sandbox Code Playgroud)

加载相关实体的所有其他方式 - 如投影,直接SQL语句甚至显式加载而不分配给导航集合,即使用.Load()而不是.Query().ToList()在上面的最后一个代码片段中 - 将不会修复关系并将导航集合留空.

如果您打算主要执行SQL查询而不是LINQ查询,我可以看到的唯一选择是您编写自己的关系管理.除了两个相关实体的表之外,您还必须查询链接表.您可能需要一个帮助器类型(不是实体)和集合,它包含链接表的两个FK列值,并且可能是一个辅助例程,通过检查您找到的实体的主键值来填充导航集合附加在DbSet<T>.Local集合中,辅助集合中的FK值.