当前位置:  开发笔记 > 编程语言 > 正文

最大还是默认?

如何解决《最大还是默认?》经验,为你挑选了10个好方法。

从可能不返回任何行的LINQ查询中获取Max值的最佳方法是什么?如果我这样做

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter).Max

当查询没有返回任何行时,我收到错误.我可以

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter _
         Order By MyCounter Descending).FirstOrDefault

但对于这样一个简单的请求,这感觉有点迟钝.我错过了一个更好的方法吗?

更新:这是后面的故事:我正在尝试从子表中检索下一个资格计数器(遗留系统,不要让我开始......).每个患者的第一个资格行总是1,第二个是2,等等(显然这不是子表的主键).因此,我正在为患者选择最大现有计数器值,然后向其中添加1以创建新行.当没有现有子值时,我需要查询返回0(因此添加1会给我一个计数器值1).请注意,我不想依赖子行的原始计数,以防遗留应用程序在计数器值中引入间隙(可能).我试图让这个问题过于通用我不好.



1> Jacob Proffi..:

由于DefaultIfEmpty未在LINQ to SQL中实现,因此我对其返回的错误进行了搜索,并发现了一篇引人入胜的文章,介绍了聚合函数中的空集.总结一下我发现的内容,你可以通过在你的选择中转换为可空来解决这个限制.我的VB有点生疏,但我认为它会像这样:

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select CType(y.MyCounter, Integer?)).Max

或者在C#中:

var x = (from y in context.MyTable
         where y.MyField == value
         select (int?)y.MyCounter).Max();


@Neil:请回答.DefaultIfEmpty对我不起作用:我想要一个`DateTime`的`Max`.`Max(x =>(DateTime?)x.TimeStamp)`仍然是唯一的方法..
LINQ to SQL支持DefaultIfEmpty的两个重载之一 - 不带参数的那个.

2> Eddie Deyo..:

我只是遇到了类似的问题,但我在列表而不是查询语法上使用LINQ扩展方法.对Nullable技巧的转换也适用于那里:

int max = list.Max(i => (int?)i.MyCounter) ?? 0;



3> Jacob Proffi..:

听起来像是一个案例DefaultIfEmpty(未经测试的代码如下):

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter).DefaultIfEmpty.Max


谢谢,这正是我想要的.使用扩展方法:`var colCount = RowsEnumerable.Select(row => row.Cols.Count).DefaultIfEmpty().Max()`

4> yfeldblum..:

想想你在问什么!

{1,2,3,-1,-2,-3}的最大值显然为3. {2}的最大值显然为2.但空集{}的最大值是多少?显然这是一个毫无意义的问题.简单地没有定义空集的最大值.试图得到答案是一个数学错误.任何集合的最大值本身必须是该集合中的元素.空集没有元素,因此声称某个特定数字是该集合的最大值而不在该集合中是一个数学上的矛盾.

正如程序员要求它除以零时计算机抛出异常是正确的行为,因此当程序员要求它取出空集的最大值时,计算机抛出异常是正确的行为.除以零,取出空集的最大值,摆动spacklerorke,乘坐飞行的独角兽到Neverland都是毫无意义的,不可能的,未定义的.

现在,你真正想做的是什么?


我经常试图将我的独角兽飞到梦幻岛,我冒犯了你的建议,即我的努力毫无意义且未定义.
无论查询是在对象内存中执行还是在行上的数据库上执行查询,Linq通常都应该产生相同的结果.Linq查询是Linq查询,无论使用哪个适配器,都应忠实执行.
我认为这种论证是对的.它是清晰的linq-to-sql,而在sql Max中,超过零的行被定义为null,不是吗?

5> David Schmit..:

您可以随时添加Double.MinValue到序列中.这将确保至少有一个元素,并且Max仅当它实际上是最小值时才返回它.要确定哪个选项是更有效的(Concat,FirstOrDefaultTake(1)),你应该进行适当的标杆.

double x = context.MyTable
    .Where(y => y.MyField == value)
    .Select(y => y.MyCounter)
    .Concat(new double[]{Double.MinValue})
    .Max();



6> beastieboy..:
int max = list.Any() ? list.Max(i => i.MyCounter) : 0;

如果列表中有任何元素(即非空),则它将占用MyCounter字段的最大值,否则将返回0.


这不会运行2个查询吗?

7> 小智..:

从.Net 3.5开始,您可以使用DefaultIfEmpty()将默认值作为参数传递.类似以下方式之一:

int max = (from e in context.Table where e.Year == year select e.RecordNumber).DefaultIfEmpty(0).Max();
DateTime maxDate = (from e in context.Table where e.Year == year select e.StartDate ?? DateTime.MinValue).DefaultIfEmpty(DateTime.MinValue).Max();

查询NOT NULL列时允许第一个,第二个是用于查询NULLABLE列的方式.如果使用不带参数的DefaultIfEmpty(),则默认值将定义为输出类型,如" 默认值表"中所示.

生成的SELECT不会那么优雅,但它是可以接受的.

希望能帮助到你.



8> tvanfosson..:

我认为问题是当查询没有结果时你想要发生什么.如果这是一个例外情况,那么我将查询包装在try/catch块中并处理标准查询生成的异常.如果可以让查询返回没有结果,那么你需要弄清楚在这种情况下你想要的结果.可能是@ David的回答(或者类似的东西会起作用).也就是说,如果MAX总是为正,那么将已知的"坏"值插入列表中就足够了,只有在没有结果时才会选择该值.一般来说,我希望查询检索最大值的查询有一些数据可以处理,我会去try/catch路由,否则你总是被迫检查你获得的值是否正确.一世'

Try
   Dim x = (From y In context.MyTable _
            Where y.MyField = value _
            Select y.MyCounter).Max
   ... continue working with x ...
Catch ex As SqlException
       ... do error processing ...
End Try



9> Rex Miller..:

另一种可能性是分组,类似于在原始SQL中如何处理它:

from y in context.MyTable
group y.MyCounter by y.MyField into GrpByMyField
where GrpByMyField.Key == value
select GrpByMyField.Max()

唯一的事情是(在LINQPad中再次测试)切换到VB LINQ风格会给分组子句带来语法错误.我确信概念等价物很容易找到,我只是不知道如何在VB中反映它.

生成的SQL将是以下内容:

SELECT [t1].[MaxValue]
FROM (
    SELECT MAX([t0].[MyCounter) AS [MaxValue], [t0].[MyField]
    FROM [MyTable] AS [t0]
    GROUP BY [t0].[MyField]
    ) AS [t1]
WHERE [t1].[MyField] = @p0

嵌套的SELECT看起来很蹩脚,就像查询执行会检索所有行然后从检索到的集合中选择匹配的一样......问题是SQL Server是否将查询优化为类似于将where子句应用于内部SELECT的东西.我现在正在调查......

我不太精通解释SQL Server中的执行计划,但看起来当WHERE子句在外部SELECT上时,导致该步骤的实际行数是表中的所有行,而不是匹配的行当WHERE子句在内部SELECT上时.也就是说,当考虑所有行时,看起来只有1%的成本转移到下一步,并且无论哪种方式只有一行从SQL Server返回,所以也许它在宏观方案中没有那么大的区别.



10> Dom Ribaut..:

我迟到了,但我有同样的担忧......

从原始帖子中重新编写代码,您需要定义的集合S的最大值

(From y In context.MyTable _
 Where y.MyField = value _
 Select y.MyCounter)

考虑到你的上次评论

可以说,当没有可供选择的记录时,我知道我想要0,这肯定会对最终的解决方案产生影响

我可以将你的问题改为:你想要{0 + S}的最大值.看起来像concat的建议解决方案在语义上是正确的:-)

var max = new[]{0}
          .Concat((From y In context.MyTable _
                   Where y.MyField = value _
                   Select y.MyCounter))
          .Max();

推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有