如何在Linq Query中应用自我联接?

时间:2019-06-27 15:07:41

标签: c# linq nhibernate linq-to-sql

Books Table

Id  VendorId   ASIN   Price
--  --------   ----   ------
 1   gold123    123     10
 2   sil123     123     11
 3   gold456    456     15
 4   gold678    678     12
 5   sil456     456     12
 6   gold980    980     12

我想编写一个linq查询,如果 sil 供应商ID不存在,它将返回与每个黄金相对应的行。供应商ID的后三位是该行中相应的ASIN列。

Ex-对于gold123,对应的sil123存在,因此不会返回行,但是对于gold678和gold980,对应的sil不存在。因此这些行将被返回。

我尝试关注

     var gold = _repository.Query<Books>().Where(x => 
                  x.VendorId.Contains("gold"))
                 .OrderBy(x => x.Id).Skip(0).Take(500).ToList();

    var asinsForGold = gold.Select(x => x.ASIN).ToList();



  var correspondingSilver = _repository.Query<Books>().Where(x => 
                            x.VendorId.Contains("sil") 
                           && asinsForGold.Contains(x.ASIN)).ToList();

var correspondingSilverAsins = correspondingSilver.Select(x => x.ASIN).ToList();

var goldWithoutCorrespondingSilver = gold.Where(x => 
                                !correspondingSilverAsins.Contains(x.ASIN));

我们可以采用自联接还是更好的方法仅在一个查询中而不是两个查询和其他几个列表语句中获得结果。

2 个答案:

答案 0 :(得分:2)

这只是另一个谓词,“不存在相应的白银供应商”:

var goldWoSilver = _repository.Query<Books>()
    .Where(x => x.VendorId.Contains("gold"))
    .Where(x => !_repository.Query<Books>()
        .Any(s => s.ASIN == x.ASIN
               && s.VendorId.Contains("sil"))
    .OrderBy(x => x.Id).Skip(0).Take(500).ToList();

在许多情况下,这是成功的秘诀:从您要返回的实体开始查询,仅添加谓词。通常,不应将联接用于过滤,而只能用于收集相关数据,尽管在这种情况下,应使用导航属性来隐式转换为SQL联接。

答案 1 :(得分:0)

看看是否有帮助-

var goldWithoutCorrespondingSilver = from b1 in books
                                  join b2 in books on b1.ASIN equals b2.ASIN
                                  where b1.VendorId.Contains("gold")
                                  group b2 by b1.VendorId into g
                                  where !g.Any(x => x.VendorId.Contains("sil"))
                                  select g.FirstOrDefault();

我所做的是-

  • 与ASIN匹配的选定记录
  • 按VendorID分组
  • 选定的没有 sil