如何在聚合之前将值转换为 long?

Posted

技术标签:

【中文标题】如何在聚合之前将值转换为 long?【英文标题】:How to cast a value to long before aggregating it? 【发布时间】:2019-04-08 18:04:16 【问题描述】:

从 EF 核心 2.1.4 开始,如果我们在聚合之前将 int 值转换为 longlong?(可能是为了避免算术溢出),此转换不会影响生成的查询,并且无论如何都会发生溢出.

using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;

namespace EfCoreBugs

  class Program
  
    static void Main(string[] args)
    
      using (var dbContext = new MyDbContext())
      
        Console.WriteLine(dbContext.Payments.Sum(x => (long?)x.Amount));
      
      Console.ReadLine();
    

    public class MyDbContext : DbContext
    
      protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      
        optionsBuilder.UseSqlServer(@"Server=.;Database=EfCoreBugs;Trusted_Connection=True;MultipleActiveResultSets=True;");
      
      public DbSet<Payment> Payments  get; set; 
    

    public class Payment
    
      public int Id  get; set; 
      public int Amount  get; set; 
    
  

生成的查询是:

SELECT SUM([x].[Amount])
FROM [Payments] AS [x]

有没有办法解决这个溢出问题? (除了把Amount的数据类型改成long

【问题讨论】:

dbContext.Payments.Select(x =&gt; (long)x.Amount).Sum(); ?这行得通吗,只是猜测 @TheGeneral 不,仍然会创建相同的查询。我也试过:dbContext.Payments.Select(x =&gt; new A = (long?)x.Amount ).Sum(z =&gt; z.A) 失败了。 也可以试试Convert.ToInt64(x.Amount) 它可能会也可能不会起作用 当然,一种解决方法是在数据库之外进行求和(当然可能对性能产生严重影响),如dbContext.Payments.Select(x =&gt; x.Amount).AsEnumerable().Sum(x =&gt; (long?)x)。但我认为您希望在数据库上完成总和。 @TheGeneral Convert.ToInt64(x.Amount) 转换为 SELECT SUM(CONVERT(bigint, [x].[Amount])) FROM [Payments] AS [x] 并且运行时不会溢出。你能把它写成答案吗? 【参考方案1】:

试试Convert.ToInt64(x.Amount)

它可以翻译成

SELECT SUM(CONVERT(bigint, [x].[Amount])) FROM [Payments] AS [x] 

并运行而不会溢出

为未来的读者。这实际上取决于 ORM,它可能并非在所有情况下都有效

【讨论】:

只是出于好奇:如果[Payments] 表不包含任何行(或者如果[Amount] is null 在所有行中,对于允许为空的列)生成的SQL 将产生null,而 C# 变量的类型为 long,不支持 null。在这种情况下,你会在 C# 中看到 0 吗? 是的,但它仍然很有趣。在 .NET Framework 本身中,Convert.ToInt64((object)null) 将成功并返回 0L。如果您将 int?HasValue false 放入 Convert.ToInt64(·),则使用此重载。但是我这里没有 EF,所以我没有测试那里发生了什么。 @JeppeStigNielsen 是的,我在手机上,所以我也无法测试它

以上是关于如何在聚合之前将值转换为 long?的主要内容,如果未能解决你的问题,请参考以下文章

请教在C++里如何把string类型转换成long型?

如何强制 Flow 将值转换为另一种类型?

如何在Java中将String转换为long?

如何在猪拉丁语脚本中没有前导零时将值转换为 hhmm 格式

Seaborn:如何在绘图的 X 轴上的每个值之后添加一个“%”符号,而不是将值转换为百分比? [复制]

java中long型如何转换为int型?还有long[ ]可以转换为int吗?