EF 6过滤子集合

11

我正在尝试将旧的Linq2Sql项目迁移到EF6,但遇到以下问题。

该项目是多语言的(即所有文本都有多个翻译),并且我有以下数据库结构:

数据库表格示例

如何以当前语言ID过滤所有ExampleEntity1对象和所有LocalizedContent记录?

我可以使用以下代码加载所有ExampleEntity1对象和所有LocalizedContent记录:dc.ExampleEntity1.Include(ee => ee.TextEntry.LocalizedContents);

在Linq2Sql中,我可以使用loadOptions.AssociateWith过滤LocalizedContent记录,但我找不到EF6的解决方案。

我看到了类似的旧问题(发布了2-3年),我只是想知道是否有EF6的解决方案。这对我来说是非常重要的功能,因为我的项目中有数十个实体,我不想为每个选择查询创建自定义对象。

我还发现了EntityFramework.DynamicFilters nuget软件包,它可以帮助解决我的问题,但如果可能的话,我更愿意使用“本地”的EF6功能。


有一个想法,但可能不适用于您的情况:创建一个自定义数据库函数,该函数接受当前语言ID和TextEntryId,并返回正确的LocalizedContents。只是提出这个想法,希望能激发一些灵感。 - Michael Richardson
只是出于兴趣...为什么不将textentry中的fakefield移动到localizedContent并删除表格textentry呢?这样不会失去任何东西,而且可以简化事情。因为你就不必再通过另一个链接表了...我看不出它除了fakefield之外还有什么用处...而fakefield可以移动到localizedContent中... - Seabizkit
如果你想使用本机EF方法,你最终将通过EF6的新拦截API拦截命令树。如果你这样做了,最终你会重新发明EntityFramework.DynamicFilters。我建议你使用Nuget包。 - Gert Arnold
3个回答

4

如果您想在查询数据库时执行过滤,则必须使用Query方法(从EF6开始):

Query方法提供了访问Entity Framework在加载相关实体时将使用的底层查询的方式。然后,您可以使用LINQ对查询应用过滤器,然后使用调用LINQ扩展方法(例如ToList、Load等)执行它。

using (var context = new BloggingContext()) 
{ 
  var blog = context.Blogs.Find(1); 

  // Load the posts with the 'entity-framework' tag related to a given blog 
  context.Entry(blog) 
    .Collection(b => b.Posts) 
    .Query() 
    .Where(p => p.Tags.Contains("entity-framework") 
    .Load(); 

   // Load the posts with the 'entity-framework' tag related to a given blog  
   // using a string to specify the relationship  
   context.Entry(blog) 
     .Collection("Posts") 
     .Query() 
     .Where(p => p.Tags.Contains("entity-framework") 
     .Load(); 
}

然而,明显的缺点是您需要针对每个条目执行此操作,并且每个Load调用都会执行针对数据库的查询。
除非这是您的硬性要求,否则我建议仅加载所有本地化内容,并在内存中过滤以使用所选语言。我相信性能不会成为问题。

1
从我这里开始,计算机的值增加了1。 - Seabizkit

2
请注意,目前无法过滤加载的相关实体。包含关键字将始终引入所有相关实体。
参考链接:Msdn Reference。
var result = dc.ExampleEntity1.Include(ee =>ee.TextEntry.LocalizedContents)
               .Select(x=>new
               {
                  //Try anonymous or a projection to your model.
                  //As this Select is IQuerable Extension it will execute in the data store and only retrieve filtered data.
                  exampleEntity = x,
                  localizedContetnt = x.TextEntry.LocalizedContents.Where(g=>g.Id==YourKey),
               }).FirstOrDefault();   

您可以尝试使用匿名投影来过滤“包含实体”中的内容。

实体框架团队正在处理此问题,您可以在此处投票

类似答案


我曾认为在EF中必须指定所有的Include。例如,'dc.ExampleEntity1.Include(ee =>ee.TextEntry).Include(ee =>ee.TextEntry.LocalizedContents)'。现在它是否具有了自动识别链接表以访问LocalizedContents表的能力? - Seabizkit

-1

由于include的工作方式,这个代码片段尚未经过测试和优化,性能不是很完美... 我会手动处理它,但这里有一个你可以参考的示例。

var result = dc.ExampleEntity1
             .Include(x => x.TextEntry)
             .Include(x => x.TextEntry.LocalizedContents)
             .Include(x => x.TextEntry.LocalizedContents.Local)
             .Where(x => x.id == 'ExampleEntity1Key'
                      && x.TextEntity.LocalContent.Local.Id == 'Value'
              )
             .FirstOrDefault();

这将得到一个ExampleEntity1对象,其中包含所有导航预加载...其中Local与id匹配。

然后,您可以像这样获取Local..

var listLocalsForExampleEnitity = result.TextEntry.LocalizedContents.Local.ToList();

或者你可以直接从内存中调用它们。

希望这能帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接