EF Core:LINQ 选择“多对多”到“多对多”

Posted

技术标签:

【中文标题】EF Core:LINQ 选择“多对多”到“多对多”【英文标题】:EF Core: LINQ Select "many-to-many-to-many" to "many-to-many" 【发布时间】:2019-08-22 11:49:30 【问题描述】:

我确实有一个表格“参考”和一个表格“文章”,其中一篇文章引用了其他文章。

我确实有一些简单的参考资料,例如: A -> B

SQL:

select ab.*
from Article a
inner join Reference ab on ab.ArticleFromId = a.Id
inner join Article b on b.Id = ab.ArticleToId
where a.ArticleNo = "1234"

C# LINQ:

_context.Reference
   .Where(r => r.ArticleFromNavigation.ArticleNo.Equals("1234"));

我也有类似的参考链:A -> B -> C (假设一条链中最多只有 3 篇文章)

SQL:

select ab.ArticleFromId, bc.ArticleToId
from Article a
inner join Reference ab on ab.ArticleFromId = a.Id
inner join Article b on b.Id = ab.ArticleToId
inner join Reference bc on bc.ArticleFromId = b.Id
inner join Article c on c.Id = bc.ArticleToId
where a.ArticleNo = "1234"

这在 SQL 中很容易,因为结果只是与附加连接相乘,但我不知道如何在 LINQ 中编写。

我希望它是这样的(这是行不通的):

_context.Reference
   .Where(r => r.ArticleFromNavigation.ArticleNo.Equals("1234"))
   .Select(r => new Reference
   
       ArticleFromNavigation = r.ArticleFromNavigation, //this is article "A"
       ArticleToNavigation = r.ArticleToNavigation.ReferenceArticleToNavigations //this wont work as it's a iCollection
   ).AsNoTrackable();

在这里,我想要“A -> C”的“参考”类型的新结果。 我想我必须在“新参考”部分之前包含/然后包含/加入/选择/selectmany(?)集合,但我不知道。

有什么办法可以存档吗?

【问题讨论】:

能否将示例数据添加到文章和参考表中? 【参考方案1】:

好吧,您可以像在 SQL 中一样执行此操作,但使用导航属性而不是连接。

我将使用 LINQ 查询语法,因为它可以更好地显示相似性,而且对于此类查询,方法语法非常复杂且难以阅读:

from a in _context.Article
from ab in a.ReferenceArticleFromNavigations
let b = ab.ArticleToNavigation
from bc in b.ReferenceArticleFromNavigations
let c = bc.ArticleToNavigation
where a.ArticleNo = "1234"
select new Reference

    ArticleFromNavigation = a,
    ArticleToNavigation = c,

let 语句不是很需要(您可以直接使用引用导航属性),我将它们包括在内只是为了使 LINQ 查询更接近 SQL 查询。

实际上,在这种情况下,等效方法并没有那么糟糕 - 使用嵌套的 SelectMany 展平多个级别并使用 SelectMany 重载投影(顶部,底部)对,从而允许:

_context.Article
    .Where(a => a.ArticleNo = "1234")
    .SelectMany(a => a.ReferenceArticleFromNavigations
        .SelectMany(ab => ab.ArticleToNavigation.ReferenceArticleFromNavigations)
        // include as many `SelectMany` like the above as you wish until you hit the desired level of nesting
        .Select(bc => bc.ArticleToNavigation),
    (a, c) => new Reference
    
        ArticleFromNavigation = a,
        ArticleToNavigation = c,
    );

【讨论】:

非常感谢,这对我有帮助。 .SelectMany() 是基于方法的语法,相当于基于查询的语法中的“from”,对吧? 确实如此。基本上由几个嵌套的SelectMany 压平并投影(顶部,底部)对。 感谢您添加基于方法的语法。完美答案!【参考方案2】:

我将数据库建模为类以确保语法正确。请参阅下面的代码:

using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication107

    class Program
    
        static void Main(string[] args)
        
            Context _context = new Context();
            string ArticleNo = "1234";

            var results = (from a in _context.article.Where(x => x.Id == ArticleNo)
                           join ab in _context.reference
                              .Where(x => (x.ArticleFromId == x.ArticleToId))
                              on a.Id equals ab.ArticleFromId
                           select new  a = a, ab = ab 
                          ).Select(r => new Reference()
                          
                              ArticleFromNavigation = r.a,
                              ArticleToNavigation = r.a.ReferenceArticleToNavigations.ToList() 
                          ).ToList();
        
    

    public class Context
    
        public List<Reference> reference  get; set; 
        public List<Article> article  get; set; 
    
    public class Reference
    
        public string ArticleFromId  get; set; 
        public string ArticleToId  get; set; 
        public Article ArticleFromNavigation  get; set; 
        public List<string> ArticleToNavigation  get; set; 
    
    public class Article
    
        public string Id  get; set; 
        public List<string> ReferenceArticleToNavigations  get; set; 
    


【讨论】:

以上是关于EF Core:LINQ 选择“多对多”到“多对多”的主要内容,如果未能解决你的问题,请参考以下文章

EF Core 过滤掉多对多关系中的重复实体

EF Core中的多对多映射如何实现?

EF Core 5,删除多对多关系

渴望加载多对多 - EF Core [关闭]

Entity Framework core 2.1 多对多选择查询

EF Core 多对多关系