DefaultIfEmpty (). Max () по-прежнему выбрасывает «Последовательность не содержит элементов». - PullRequest
4 голосов
/ 21 сентября 2019

После того, как я обновил свой проект до ядра dotnet 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; }
    }

2-е редактирование Sql произведено efcore

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

1 Ответ

0 голосов
/ 25 сентября 2019

Итак, я открыл вопрос в репозитории EF Core и получил ответ.По-видимому, это текущее поведение, которое может измениться позже.

Предлагаем использовать следующий подход

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 () на клиенте.

...