EF核心:LINQ选择“多对多”到“多对多”

时间:2019-04-01 10:28:02

标签: c# sql linq .net-core ef-core-2.1

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

我确实有一些简单的参考资料,例如: 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”的“ Reference”类型的新结果。 我想我必须在“新参考”部分之前包含/ theninclude / join / select / selectmany(?)集合,但是我没有头绪。

有什么办法可以存档吗?

2 个答案:

答案 0 :(得分:3)

好吧,您可以完全像在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,
    });

答案 1 :(得分:1)

我将数据库建模为类以获取正确的语法。参见下面的代码:

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; }
    }

}
相关问题