简体   繁体   English

LINQ 3个内连接和1个左外连接

[英]LINQ 3 Inner Joins with 1 Left Outer Join

Wondering why LINQ doesn't have a Left Join method. 想知道LINQ为什么没有Left Join方法。 I've been trying to figure this out with myriad examples on SO, but no such luck. 我一直在尝试用SO上的无数示例来解决这个问题,但是没有运气。 The other examples show simple examples with one join. 其他示例显示一个连接的简单示例。 If I group the joins then I only get references to the TradeCountries table in the select statement. 如果将联接分组,则只能在select语句中获得对TradeCountries表的引用。

Being new to LINQ, I could've had this done 4 hours ago with a simple SELECT statement, but here I'm am trying to figure out why the LeftJoin method was left out of LINQ. 作为LINQ的新手,我本可以在4个小时前用一个简单的SELECT语句完成此操作,但是在这里,我试图弄清楚为什么LeftJoin方法不包含在LINQ中。

What does the line with "LeftJoin" need to be changed to make this work? 为了使这项工作有效,需要更改带有“ LeftJoin”的行吗?

/* 
* GetTop5Distributors 
@param  int array of series IDs
*/
public List<TopDistributors> Get5TopDistributors(IEnumerable<int> seriesIds)
{
    _context = new MySQLDatabaseContext();
    var result = _context.TradesTrades
.Join(_context.TradesSeries, tt => tt.SeriesId, ts => ts.Id, (tt, ts) => new { tt, ts })
.Join(_context.TradesTradeDistributors, tsd => tsd.tt.Id, ttd => ttd.TradeId,
    (tsd, ttd) => new { tsd, ttd })
.Join(_context.TradesOrganisations, tsdto => tsdto.ttd.DistributorId, to => to.Id,
    (tsdto, to) => new { tsdto, to })
.LeftJoin(_context.TradesCountries, tsdc => tsdc.to.CountryId, tc => tc.Id, 
    (tsdc, tc) => new {tsdc, tc})
.Where(x => seriesIds.Contains(x.tsdc.tsdto.tsd.tt.SeriesId))
.Where(x => x.tsdc.tsdto.tsd.tt.FirstPartyId == null)
.Where(x => x.tsdc.tsdto.tsd.tt.Status != "closed")
.Where(x => x.tsdc.tsdto.tsd.tt.Status != "cancelled")
.GroupBy(n => new { n.tsdc.tsdto.tsd.tt.SeriesId, n.tsdc.tsdto.ttd.DistributorId })
.Select(g =>
    new TopDistributors
    {
        SeriesId = g.Key.SeriesId,
        DistributorName = g.Select(i => i.tsdc.to.Name).Distinct().First(),
        IsinNickname = g.Select(i => i.tsdc.tsdto.tsd.ts.Nickname).Distinct().First(),
        CountryName = g.Select(i => i.tc.Name).Distinct().First(),
        CommissionTotal = Math.Ceiling(g.Sum(i => i.tsdc.tsdto.ttd.Commission))
    }
)
.OrderByDescending(x => x.CommissionTotal)
.Take(5)
.ToList();

    return result;
}

Here's the rather simple select statement that is taking orders or magnitude too long to convert to LINQ. 这是相当简单的select语句,需要花费很长时间或数量级才能转换为LINQ。

SELECT
trades_trades.series_id,
trades_organisations.`name`,
trades_series.nickname,
trades_countries.name as Country_Name,
SUM(trades_trade_distributors.commission) as Commission_Total
FROM
trades_trades
JOIN trades_series
ON trades_series.id = trades_trades.series_id
JOIN trades_trade_distributors
ON trades_trades.id = trades_trade_distributors.trade_id
JOIN trades_organisations
ON trades_trade_distributors.distributor_id = trades_organisations.id
LEFT JOIN trades_countries
ON trades_organisations.country_id = trades_countries.id
WHERE trades_trades.series_id   IN (
    17,
    18)
    AND trades_trades.first_party_id IS NULL
    AND trades_trades.status <> 'closed'
    AND trades_trades.status <> 'cancelled'
GROUP BY trades_trades.series_id, trades_trade_distributors.distributor_id
ORDER BY Commission_Total DESC

Following my recipe, here is a more or less straightforward translation of the SQL to LINQ. 按照我的食谱,这是将SQL或多或少直接转换为LINQ的方法。 I moved the where to be near what it constrains, and used let to create a convenient name for the Sum , as LINQ doesn't allow you to forward reference anonymous object members. 我搬到了where是附近什么约束,并用let为营造一个方便的名字Sum ,如LINQ不允许你参考匿名对象成员转发。

var ans = from tt in trades_trades
          where new[] { 17, 18 }.Contains(tt.series_id) && tt.first_party_id == null &&
                tt.status != "closed" && tt.status != "cancelled"
          join ts in trades_series on tt.series_id equals ts.id
          join ttd in trades_trade_distributors on tt.id equals ttd.trade_id
          join to in trades_orginizations on ttd.distributor_id equals to.id
          join tc in trades_countries on to.country_id equals tc.id into tcj
          from tc in tcj.DefaultIfEmpty() // GroupJoin -> left join
          group new { tt, ts, ttd, to, tc } by new { tt.series_id, ttd.distributor_id } into tradeg
          let Commission_Total = tradeg.Sum(trade => trade.ttd.commission)
          orderby Commission_Total descending
          select new {
            tradeg.Key.series_id,
            tradeg.First().to.name,
            tradeg.First().ts.nickname,
            Country_Name = tradeg.First().tc == null ? null : tradeg.First().tc.name,
            Commission_Total
          };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM