【问题标题】:LINQ Max() with Nulls带有 Null 的 LINQ Max()
【发布时间】:2011-02-18 23:40:27
【问题描述】:

我有一个包含一堆点的列表(带有 X 和 Y 分量)。

我想获取列表中所有点的 Max X,如下所示:

double max = pointList.Max(p=> p.X);

问题是当我在列表中有一个空值而不是一个点时。解决此问题的最佳方法是什么?

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    好吧,你可以过滤掉它们:

    pointList.Where(p => p != null).Max(p => p.X)
    

    另一方面,如果您希望 nulls 被视为具有 X 坐标 0(或类似)的点,您可以这样做:

    pointList.Max(p => p == null ? 0 : p.X)
    

    请注意,如果序列为空,这两种技术都会抛出异常。一种解决方法(如果需要)是:

    pointList.DefaultIfEmpty().Max(p => p == null ? 0 : p.X)
    

    【讨论】:

    • 我不推荐使用DefaultIfEmpty。请看我的回答为什么:link
    • @Nikkelmann 我相信这是内存中实体的 LINQ 查询,没有连接到任何数据库。
    • @RamonSnir 如果是这种情况,那么两者都可以:) 但是现在人们知道不要将它用于 LinqToSql。
    • 或者更确切地说:Linq to Entities。
    • 如果他愿意,他也可以使用可以为空的类型,pointList.Max(p => p == null ? (double?)null : p.X)。请注意,对于可空类型 Max 不会抛出异常,即使是空序列也不会。
    【解决方案2】:

    如果要为空点的 X 提供默认值:

    pointList.Max(p => p == null ? 0 : p.X)
    

    或者为空列表提供默认值:

    int max = points.Where(p => p != null)
                    .Select(p => p.X)
                    .DefaultIfEmpty()
                    .Max();
    

    【讨论】:

    • 有趣的方法,我比我更喜欢它,因为它避免了条件,DefaultIfEmpty 应用于 result 类型。
    【解决方案3】:

    我不建议在这种情况下使用DefaultIfEmpty,因为与其他替代方案相比,它会产生相当大的 SQL。

    请看这个例子:

    我们有一个页面的模块列表,并希望获得“排序”列的最大值。如果列表没有记录,则返回 null。 DefaultIfEmpty 检查是否为空,当列为空时返回列数据类型的默认值。

    var max = db.PageModules.Where(t => t.PageId == id).Select(t => t.Sort).DefaultIfEmpty().Max();
    

    这会产生以下 SQL:

    exec sp_executesql N'SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Join1].[A1]) AS [A1]
        FROM ( SELECT 
            CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Sort] END AS [A1]
            FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
            LEFT OUTER JOIN  (SELECT 
                [Extent1].[Sort] AS [Sort], 
                cast(1 as tinyint) AS [C1]
                FROM [dbo].[PageModules] AS [Extent1]
                WHERE [Extent1].[PageId] = @p__linq__0 ) AS [Project1] ON 1 = 1
        )  AS [Join1]
    )  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
    go
    

    如果我们改为将该列转换为可空值并让Convert.ToInt32() 处理空值:

    var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Max(t => (int?)t.Sort));
    

    然后我们得到如下SQL:

    exec sp_executesql N'SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Extent1].[Sort]) AS [A1]
        FROM [dbo].[PageModules] AS [Extent1]
        WHERE [Extent1].[PageId] = @p__linq__0
    )  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
    go
    

    我真的可以推荐使用 ExpressProfiler 检查执行的 SQL: http://expressprofiler.codeplex.com/

    最后一个Linq表达式也可以写成:

    var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Select(t => (int?)t.Sort).Max());
    

    并且会生成相同的 SQL,但我更喜欢更简洁的 .Max(t => (int?)t.Sort)

    【讨论】:

    • 任何为您生成 SQL 的 ORM 或工具的问题在于,它们让您很容易自责。您所处理的只是代码,几乎没有人会查看生成的 SQL。这些机械翻译的问题在于它们产生“一刀切”的代码,有时,它比您可能需要的要大得多。感谢您在这篇文章中强调这一点。底线,始终检查您生成的查询! +1!!
    • +1 始终检查您生成的查询!您可以编写糟糕的 SQL(因此我们对其进行分析),但不知何故,当我们不分析(甚至不查看)它生成的 SQL 时,ORM 总是会受到指责!
    • 我正在尝试使用这种方法,但我有不同的查询语法,所以我似乎无法让 select 中的 lamda 表达式工作。我正在使用Convert.ToInt32( (from x in table join y in table 2 on x.ID equals y.ID where y.ProjectID == ProjectID select x.ObservationNum).Max()); 有没有办法使用您的语法进行连接,或者修改我的方法以获取可为空的 int 强制转换?
    • @paul-gibson 从我的脑海中尝试“.Max(t => (int?)t.Sort)”。
    • 多哈。 . .它就在您的答案中。 . .谢谢:)
    【解决方案4】:
    double max = pointList.Where(p=>p != null).Max(p=>p.X)
    

    应该可以。

    【讨论】:

      【解决方案5】:

      在表达式内部放置一个可为空的强制转换,以确保空白列表将强制转换为空。然后您可以添加默认值。

      double max = pointList.Max(p=>(double?)p.X) ?? 0;
      

      【讨论】:

        【解决方案6】:

        检查 null 对我不起作用。我使用了 DefaultIfEmpty()

           int max_sequence = _dbContext.myTable
                        .Where(e=>e.field1==param.field1
                        && e.fieldDate==param.fieldDate
                        )
                        .Select(e => e.Sequence)
                        .DefaultIfEmpty()
                        .Max();
        

        【讨论】:

          【解决方案7】:

          尝试强制转换为可空

          double max = (double?)pointList.Max(p => p.X);
          

          更多: Max or Default?

          【讨论】:

            【解决方案8】:

            为什么不简单:

            double? maxOrNull  = pointList.
                .Where(p => p != null)
                    .OrderByDescending(p => p.x)
                    .FirstOrDefault();
            double max = 0;
            if (maxOrNull.HasValue) max = maxOrNull.Value;
            

            这可以在内存列表和 Linq2Sql 中使用,而且可能也很有效。

            【讨论】:

              【解决方案9】:

              最大值为空的列如下

              var maximum = objectEntity.where(entity => entity.property != null).max(entity => entity.property.HasValue);
              

              以上语句返回实体属性的最大数量

              【讨论】:

                猜你喜欢
                • 2017-12-11
                • 1970-01-01
                • 1970-01-01
                • 2019-10-11
                • 1970-01-01
                • 2016-12-17
                • 2014-11-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多