【问题标题】:DefaultIfEmpty().Max() still throws 'Sequence contains no elements.'DefaultIfEmpty().Max() 仍然抛出“序列不包含元素。”
【发布时间】:2019-09-21 10:45:41
【问题描述】:

在我将我的项目更新到 dotnet core 3.0RC1(可能也在 preview9 中)之后,我的代码曾经可以工作

var value = context.Products.Where(t => t.CategoryId == catId).Select(t => t.Version).DefaultIfEmpty().Max();

开始投掷 System.InvalidOperationException: Sequence contains no elements。有问题的表是空的。

如果我添加ToList(),它看起来像这样DeafultIfEmpty().ToList().Max(),它会再次开始工作。找不到有关重大更改的任何信息。当我跑步时

var expectedZero = new List<int>().DefaultIfEmpty().Max();

它工作正常。这让我觉得 EF Core 可能有问题。然后我在 xUnit 中使用完全相同的设置创建了测试,但是测试通过了(表也是空的,使用 InMemoryDatabase 而不是实时 SQL Server 实例)。

我真的很困惑。 相关堆栈跟踪:

System.InvalidOperationException: Sequence contains no elements.
   at int lambda_method(Closure, QueryContext, DbDataReader, ResultContext, int[], ResultCoordinator)
   at bool Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor+QueryingEnumerable<T>+Enumerator.MoveNext()
   at TSource System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource> source)
   at TResult Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute<TResult>(Expression query)
   at TResult Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute<TResult>(Expression expression)
   at TSource System.Linq.Queryable.Max<TSource>(IQueryable<TSource> source)
   at ... (my method that run the code)

编辑

产品类别:

   [Table("tmpExtProduct", Schema = "ext")]
    public partial class Product
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Version { get; set; }

        [Column(TypeName = "datetime")]
        public DateTime ImportDate { get; set; }

        public int CategoryId { get; set; }
        public string Description { get; set; }

        [ForeignKey(nameof(Ext.Category))]
        public int CategoryId { get; set; }        

        [InverseProperty(nameof(Ext.Category.Products))]
        public virtual Category Category { get; set; }
    }

第二次修改 ef core产生的sql

exec sp_executesql N'SELECT MAX([t0].[Version])
FROM (
    SELECT NULL AS [empty]
) AS [empty]
LEFT JOIN (
    SELECT [p].[Version], [p].[CategoryId], [p].[ImportDate], [p].[Description]
    FROM [ext].[tmpExtProduct] AS [p]
    WHERE (([p].[CategoryId] = @__categoryId_0) AND @__categoryId_0 IS NOT NULL)
) AS [t0] ON 1 = 1',N'@__categoryId_0 int',@__categoryId_0=5

【问题讨论】:

  • 您能告诉我们产品类代码吗?特别是Version的属性?
  • 根据要求,但 Version 只是一个 int (但也是主键)。不过,之前没有问题。现在检查.DefaultIfEmpty() 的结果返回Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable&lt;int&gt;,结果视图包含IEnumerable,其中1 项= 0,类型为int。
  • OK 只是仔细检查它不可为空。我想我的下一个请求是查看 EF 核心生成的 SQL,因为这可能有一些额外的线索。否则,我建议您打开issue on the GitHub repo,看看您是否可以在那里找到解决方案。我可以看到InMemory support for default if empty was only added this last month 所以这可能是这里的因素
  • 已发布,但我没有看到任何异常...

标签: c# .net-core ef-core-3.0


【解决方案1】:

于是我打开issue in EF Core repo 得到了答案。显然这是当前的行为,以后可能会改变。

建议使用以下方法

var valueFail = context.Products.Where(t => t.CategoryId == catId)
                .GroupBy(e => 1)
                .Select(t => t.Max(e => e.Version))
                .ToList()[0];

这比我的解决方法DeafultIfEmpty().ToList().Max() 更好,因为它将在服务器端完成所有工作,而我的解决方案将在客户端计算 Max()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    相关资源
    最近更新 更多