InvalidCastException при использовании IncludeFilter для объекта со свойством DateTime " - PullRequest
0 голосов
/ 10 марта 2020

Я приветствую непонятное InvalidCastException, связанное с библиотекой Entity Framework Plus и, в частности, с ее методом расширения IncludeFilter.

Подводя итог, у меня есть 3 объекта: Project, Test и TestRun : - каждый проект имеет коллекцию тестов; - каждый тест имеет коллекцию TestRuns. У меня есть класс ProjectService, который реализует метод для извлечения проекта из базы данных, с возможностью выбора, какие из них являются желательными. Вот код этого метода (я сократил его до наименьшего фрагмента кода, который все еще производит то же исключение, плюс еще один фрагмент, который работает для сравнения):

private IQueryable<Project> NewQuery(ProjectIncludeOptions includes = ProjectIncludeOptions.NONE)
{
    IQueryable<Project> query = base.NewQuery();

    /* NO PROBLEM HERE: just left it for comparison. */
    if (includes.HasFlag(ProjectIncludeOptions.DOMAINS))
    {
        query =
            query
                .IncludeFilter(p => p.TestDomains.Where(td => !td.IsArchived).Select(td => td.Children.Where(tdc => !tdc.IsArchived)))
                .IncludeFilter(p => p.TestDomains.Where(td => !td.IsArchived).Select(td => td.Parent));
    }

    /* EXCEPTION CAUSED BY THE CODE BELOW */
    if (includes.HasFlag(ProjectIncludeOptions.TESTS))
    {
        query =
            query
                /* In the below code, if I remove the Where clause, or use a non-calculated property in it, then the exception disappears. */
                .IncludeFilter(p => p.Tests.Where(t => !t.IsArchived).Select(t => t.TestRuns));
    }

    return query;
}

Реализация свойства IsArchived (в Класс тестирования) выглядит следующим образом:

[NotMapped]
public virtual bool IsArchived
{
    get { return ArchivingDate.HasValue; }
    set { ArchivingDate = value ? System.DateTime.Now : (System.DateTime?)null; }
}

И место, где я на самом деле получаю InvalidCastException (исходя из вызова SingleOrDefault):

Project project = NewQuery(includes).SingleOrDefault(p => p.Id == projectId);

Полное сообщение об исключении:

System.InvalidCastException: 'Невозможно привести объект типа' System.String 'к типу' System.Int32 '.'

И трассировка стека при возникновении ошибки:

в System.Data.SqlClient.SqlBuffer.get_Int32 () в System.Data.SqlClient.SqlDataReader.GetInt32 (Int32 i) в lambda_method (закрытие, DbDataReader) в Microsoft.EnterialFrame. .TypedRelationalValueBufferFactory.Create (DbDataReader dataReader) в Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable 1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func 3 операция, Fun c3 verifySucceeded) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable 1.Enumerator.MoveNext () в System.Linq.Lookup * источник 1023 * 1, Fun c2 keySelector, IEqualityComparer 1 компаратор) в System.Linq.Enumerable.JoinIterator [TOuter, TInner, TKey, TResult] (IEnumerable 1 outer, IEnumerable 1 внутренняя, Fun c2 outerKeySelector, Func 2 innerKeySelector, Fun c3 resultSelector, IEqualityComparer 1 Comparer) + MoveNext () в System.Linq.Enumerable.GroupJoinIterator [TOuter, TInner, TKey, TResult] (IEnumerable 1 outer, IEnumerable 1 inner, Fun c2 outerKeySelector, Func 2 innerKeySelector, Fun c3 resultSelector, IEqualityComparer 1 Comparer) + MoveNext () в System.Linq.Enumerable.SelectManyIterator [TSource, TCollection, TResult] (IEnumerable 1 source, Func 2 collectionSelector , Забава Z.EntityFramework.Plus.QueryFutureEnumerable * (1035 * 1 перечислитель) в Z.EntityFramework.Plus.QueryFutureEnumerable 1.SetResult(DbDataReader reader) at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries() at Z.EntityFramework.Plus.QueryFutureValue 1. .Обслуживание. Impl.ProjectService.Get (Int32 projectId, ProjectIncludeOptions включает)

Больше всего меня сбивает с толку то, что я не получаю никаких исключений при использовании части ProjectIncludeOptions.DOMAINS, которая, по-видимому, реализована точно так же (свойство IsArchived также идентично для объектов TestDomain).

Более того, все мои объекты (Project, Test, TestRun и TestDomain) имеют свойства DateTime и они, похоже, играют роль в этой проблеме. Действительно, если я отмечу все свойства DateTime из Test и TestRun как [NotMapped] (сохраняя весь код в ProjectService, как показано выше), то исключение исчезнет! Если я оставлю только одно сопоставленное свойство DateTime (независимо от того, какое именно), то сработает исключение. Однако они, похоже, не вызывают каких-либо проблем с TestDomain и приведенным выше кодом.

Имеет ли это какой-либо смысл для кого-либо из вас?

Мне удалось обойти это Я просто удалил предложение WHERE внутри IncludeFilter (потому что это не критично для моего проекта), но я был бы рад хотя бы понять, что происходит, и найти решение для него. :)

1 Ответ

0 голосов
/ 11 марта 2020

Я не уверен, что это именно та проблема, но цель IncludeFilter - создать запрос и выполнить фильтрацию на стороне базы данных.

Однако свойство IsArchived не отображается. Это означает, что невозможно создать запрос, который будет выполняться на стороне базы данных (это может быть возможно в EF Core 2.x из-за оценки на стороне клиента).

Убедитесь, что фильтрующая часть может все будет сделано в базе данных.

Это выглядит возможным при использовании непосредственно свойства ArchivingDate.

...