如何手动加载相关实体的N:N的关系?如何手动加载相关实体的N:N的关系?(How to manual

2019-05-12 06:05发布

我使用EF5当的关系是1:N,如果我想加载相关实体我做到以下几点:

  • 随着T-SQL我从数据库中加载有了这样的T-SQL的主要实体:

     select * from MainEntities where ... 
  • 与T-SQL我加载相关实体

     select * from RelatedEntities where IDMainEntity IN (---) 

此时EF填充相关实体的主要实体的属性导航。 此外,在每个实体的类型在本地物业dbContext我有每种类型的所有实体。

但是,如果我做同样的一个N:N的关系,我没有关系的中间表的实体,当我执行查询我在当地的dbContext每种类型的实体,但物业导航不填充。

我想知道是什么原因,如果它存在一些替代。

因为我想用T-SQL的创建动态查询,我用这种方式。 如果我使用预先加载我没有同样的灵活性,以动态查询比我使用TSQL,而且效率较低。 如果我使用显式装载我做N个附加查询,在主要企业的业绩,用我的方式,我只是一个额外的查询每个记录中的一个,因为我得到的所有相关实体的一次。 如果我使用延迟加载我有同样的问题,N额外的查询。

N:为什么当关系是N EF不填充相关的属性?

谢谢。

Answer 1:

你所谈论的功能被称为关系跨度关系Fixup时确实-因为你已经注意到了-它并不适用于许多一对多的关系的工作。 它只能如果关联的至少一端具有多重1(或0..1),即它为一个一对多或一对一的一对一的关系。

关系跨度依赖于拥有一个外键的实体。 这不要紧,如果它在相应的数据库表显式外键属性( 外键关联 ),或者只是一个外键列,而不在模式( 独立协会 )的属性。 在这两种情况下,当实体被加载的FK值将被加载到上下文。 在此基础上外键值EF能够找出是否具有相同的主键值,因为这FK值相关的实体附加到上下文,如果是,它可以“修正的关系”,即它可以填充导航正确的属性。

现在,在一个多一对多的关系,两者相关实体没有一个外键。 外国密钥存储在这种关系的链接表 - 如你所知 - 链接表中没有相应的模型实体。 其结果是,外键将永远不会被加载,因此上下文无法确定哪些附加实体有关,并不能修正内容的许多一对多的关系,并填充导航集合。

其中EF会支持你打造一个多一对多的关系与人口导航集合了正确的对象图唯一的LINQ查询渴望载入中...

var user = context.Users.Include(u => u.Roles).First();

...或延迟加载...

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)

...或者,结果导航集的直接分配明确加载:

var user = context.Users.First();
user.Roles = context.Entry(user).Collection(u => u.Roles).Query().ToList();

所有其他的方式来加载相关实体-样突出,直接的SQL语句,甚至明确的装载,没有分配到导航集合,即使用.Load()代替.Query().ToList()在过去的代码段中-韩圆“T修正内容的关系,将离开导航集合空。

如果您打算主要执行SQL查询,而非LINQ查询,我可以看到的唯一选择是,你写你自己的关系管理。 你将不得不查询链接表中除了两个相关实体的表。 你可能需要一个辅助型(这不是一个实体)和收集保存链接表,并可能是一个辅助函数,通过检查你的发现实体的主键值填充导航集的两个FK列值附着在DbSet<T>.Local辅助集合中收集和FK值。



Answer 2:

要添加上@Slauma答案:

最近,我遇到了同样的问题,感到沮丧的是,导航属性不被调用后设置Query().Where().Load() ,但我可以看到的物体装入的DbContext。

我需要集合是我的主要对象的一部分,并使用它,就像任何其他的导航性能,而不仅仅是管理一个单独的集合,所以我这样做:

project.Labels = this.Context
                    .Entry (project)
                    .Collection (p => p.Labels)
                    .Query ()
                    .Where (l => l.CreateUserName == this.UserId)
                    .ToList();

这里的问题是,EF认为我增添了新的关系,这是我不能责怪它,但它不是我想要的。 其结果是,试图拯救工程的对象我有一个异常时,EF试图插入关系到链接表,因为使用相同的密钥(专案编号+ labelId)已存在某行的时候。

所以,最终被重置项目和标签之间的关系的状态:

foreach (Label l in project.Labels)
                {
                    ((System.Data.Entity.Infrastructure.IObjectContextAdapter)this.Context.AsDbContext ()).ObjectContext.ObjectStateManager.ChangeRelationshipState<Project> (project, l, p => p.Labels, EntityState.Unchanged);
                }

从那以后,我能够使用的标签属性,就像任何其他的导航性能,不关心在幕后这是一个许多一对多的关系。



文章来源: How to manually load related entities in a N:N relationship?