【问题标题】:How to groupby with inner join using linq lamba expression如何使用 linq lambda 表达式通过内部连接进行分组
【发布时间】:2020-10-02 08:50:40
【问题描述】:

我正在尝试将 sql 存储过程转换为 linq。我遇到了 groupby 和 inner join 的问题。

这是我尝试过的:

var r = _context.Table1
    .GroupBy(x => new { x.OptionId, x.Years, x.Strike })
    .Join(_context.Table2,
        oc => oc.OptionId, o => o.OptionId, (oc, o) => new
        {
            OptionsCosts = oc,
            Options = o
        }).Where(x => x.Options.OptionType == 1
                && x.Options.QualifierId != null
                && x.Options.CreditingMethod != "xxx")
    
    .Select(y => new DataModel.Table1()
    {
        Years = y.Select(a => a.OptionsCosts.Years).FirstOrDefault(),
        Strike = y.Select(a => a.OptionsCosts.Strike).FirstOrDefault(),
        Value = y.Select(a => a.OptionsCosts.Value).FirstOrDefault(),
        ChangeUser = y.Select(a => a.OptionsCosts.ChangeUser).FirstOrDefault(),
        ChangeDate = DateTime.Now,
        OptionId = y.Select(a => a.OptionsCosts.OptionId).FirstOrDefault()
    });

这是我要转换的 SQL:

SELECT o2.OptionId, o2.Years, o2.Strike, SUM(d2.Weights) as 'TotalWeight', COUNT(*) as 'Counts'
FROM Table1 o2
INNER JOIN @Dates d2  --this is a temp table that just holds dates. I was thinking just a where statement could do it???
  ON d2.EffectiveDate = o2.EffectiveDate
INNER JOIN Table2 od2
   ON od2.OptionId = o2.OptionId
  AND od2.OptionType = 1
  AND od2.qualifierid is null
  AND od2.CreditingMethod <> 'xxx' --28095
GROUP BY o2.OptionId,o2.Years, o2.Strike

我的数据有问题,所以我确定我做错了什么。

【问题讨论】:

  • linq-to-sql 或 entity-framework-core,是哪个?
  • 内存中是否还有@Dates 表?
  • 不管是什么,LINQ 都不能替代 SQL。从实体之间的关系生成 JOIN 是 ORM 的工作。 ORM 旨在将对象映射到关系表和视图,而不是执行任意 SQL 查询。表变量超出了任何 ORM 的范围。
  • 与其尝试使用 LINQ 重写 SQL 查询,不如创建一个视图或函数并将您的对象映射到它。您可以使用FromSqlRawFromSqlInterpolated 将SQL 查询用作LINQ 查询的起点。表变量是个问题——它从何而来,如何创建?
  • 好吧,看看您的查询:&amp;&amp; x.Options.QualifierId != null 和 SQL:AND od2.qualifierid is null。你看出区别了吗?

标签: c# linq lambda linq-to-sql entity-framework-core


【解决方案1】:
var table1=_context.Table1
.groupBy(o2=> new{
o2.OptionId
, o2.Years
, o2.Strike
})
.select(s=> new{
s.key.OptionId
, s.key.Years
, s.key.Strike
,TotalWeight=s.sum(x=>x.Weights)
,Counts=o2.count(c=>c.OptionId)
}).tolist();
var result=table1
.Join(_context.Table2,oc => oc.OptionId, o => o.OptionId, (oc, o) => new{ OptionsCosts = oc,  Options = o })
.Where(x => x.Options.OptionType == 1
                && x.Options.QualifierId != null
                && x.Options.CreditingMethod != "xxx")
.select(x=> new {
    x.oc.OptionId,  x.oc.Years,  x.oc.Strike,  x.oc.TotalWeight, x.oc.Counts
}).tolist();

【讨论】:

    【解决方案2】:

    小建议,在重写SQL查询时,使用与SQL接近的LINQ Query语法,更有效避免错误。

    var dates = new List<DateTime>() { DateTime.Now }; // fill list
    
    var query = 
        from o2 in _context.Table1
        where dates.Contains(o2.EffectiveDate)
        from od2 in _context.Table1.Where(od2 => // another way to join
             od2.OptionId == o2.OptionId
          && od2.OptionType == 1
          && od2.qualifierid == null
          && od2.CreditingMethod != "xxx")
        group o2 by new { o2.OptionId, o2.Years, o2.Strike } into g
        select new 
        {
           g.Key.OptionId, 
           g.Key.Years, 
           g.Key.Strike, 
           Counts = g.Count()
           // SUM(d2.Weights) as 'TotalWeight', -this one is not available because dates in memory
        };
    

    如果您刚开始并尝试在 LINQ 上重写程序 - EF Core 是个坏主意。 IQueryable 支持太有限,通常您会为每个复杂的 LINQ 查询而战。 试试linq2db,它支持临时表,你的存储过程可以重写为相同的 LINQ 查询。或者,您可以使用 linq2db.EntityFrameworkCore 来扩展 EF Core 功能。

    免责声明。我是此扩展程序的创建者,也是 linq2db 创建者的创建者。

    【讨论】:

    • 不确定“更多的错误证明”试图说什么,但查询和流利/lambda语法在功能上没有区别。
    • 出错的机会更少。不完全是错误,但它限制了创建不可翻译的 LINQ 查询的方法。
    • 我不确定这是不是真的,(您可以使用查询语法生成GroupJoinSelectMany),但查询语法中可能的查询肯定更少。
    • 使用查询语法,您可以生成 Where、SelectMany、Join、GroupJoin、OrderBy、GroupBy - 这是非常逐字逐句的构造,尤其是在最后有多个连接和分组的情况下。编译器做脏活来创建透明类。肯定有First、Distinct、Concat、Union等不适用于查询语法,所以需要合理混合。无论如何,查询语法更严格,以防止查询转换为 SQL 出现问题,并且从 SQL 的角度来看,它的可读性更好。任何查询语法都可以转换为 lambda 语法,但在反向转换中为 false。
    • 您认为哪些 lambda 语法使用支持的操作不能转化为查询语法?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多