IQueryable ToListAsync жалуется на нарушение ограничения при использовании пользовательской структуры - PullRequest
2 голосов
/ 05 июля 2019

Context

Я пытаюсь написать функцию для преобразования IQueryable<T> в IQueryable<CustomType<T, K>>, которая затем может быть преобразована в IEnumerable<CustomType<T, K>> при необходимости.

Проблема

Дано:

public struct CustomType<TModel, TKey>
{
    public TKey Key { get; set; }
    public TModel Value { get; set; }
}

, если я напишу:

var list = await query
    .Select(selectExpression) // Selects into `CustomType<T, K>`
    .Where(whereExpression)
    .OrderBy(orderByExpression)
    .Select(x => new { Value = x.Value })
    .ToListAsync();

, где selectExpression - это построенное во время выполнения выражение, эквивалентное:

x => new CustomType<T, K> { Key = ..., Value = ... }

тогда все работает как положено, и selectExpression, который создается во время выполнения, преобразуется в одно выражение SQL.

Но если в любой момент я возвращаю CustomType<T, K>, как в:

var list = await query
    .Select(selectExpression) // Selects into `CustomType<T, K>`
    .ToListAsync();

Затем EF Core жалуется, что в какой-то функции отслеживания сущностей CustomType<T, K> нарушает некоторое ограничение TIn (зачем пытаться отследить пользовательский тип?)

Этот код конкретной ошибки (для * 1031)*):

GraphQL.ExecutionError: GenericArguments[1], 'CustomType`2[OtherType,System.Int32]', on 'System.Collections.Generic.IAsyncEnumerable`1[TOut] _TrackEntities[TOut,TIn](System.Collections.Generic.IAsyncEnumerable`1[TOut], Microsoft.EntityFrameworkCore.Query.QueryContext, System.Collections.Generic.IList`1[Microsoft.EntityFrameworkCore.Query.Internal.EntityTrackingInfo], System.Collections.Generic.IList`1[System.Func`2[TIn,System.Object]])' violates the constraint of type 'TIn'. ---> GraphQL.Conventions.Execution.FieldResolutionException: GenericArguments[1], 'CustomType`2[OtherType,System.Int32]', on 'System.Collections.Generic.IAsyncEnumerable`1[TOut] _TrackEntities[TOut,TIn](System.Collections.Generic.IAsyncEnumerable`1[TOut], Microsoft.EntityFrameworkCore.Query.QueryContext, System.Collections.Generic.IList`1[Microsoft.EntityFrameworkCore.Query.Internal.EntityTrackingInfo], System.Collections.Generic.IList`1[System.Func`2[TIn,System.Object]])' violates the constraint of type 'TIn'. ---> System.ArgumentException: GenericArguments[1], 'Persistence.IQueryableExtensions+OrderedGroupItem`2[OtherType,System.Int32]', on 'System.Collections.Generic.IAsyncEnumerable`1[TOut] _TrackEntities[TOut,TIn](System.Collections.Generic.IAsyncEnumerable`1[TOut], Microsoft.EntityFrameworkCore.Query.QueryContext, System.Collections.Generic.IList`1[Microsoft.EntityFrameworkCore.Query.Internal.EntityTrackingInfo], System.Collections.Generic.IList`1[System.Func`2[TIn,System.Object]])' violates the constraint of type 'TIn'. ---> System.Security.VerificationException: Method Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider._TrackEntities: type argument 'Persistence.IQueryableExtensions+OrderedGroupItem`2[OtherType,System.Int32]' violates the constraint of type parameter 'TIn'.
   at System.RuntimeMethodHandle.GetStubIfNeeded(RuntimeMethodHandleInternal method, RuntimeType declaringType, RuntimeType[] methodInstantiation)
   at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
   --- End of inner exception stack trace ---
   at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
   at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.TrackEntitiesInResults[TResult](QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
   at System.Linq.AsyncEnumerable.Aggregate_[TSource,TAccumulate,TResult](IAsyncEnumerable`1 source, TAccumulate seed, Func`3 accumulator, Func`2 resultSelector, CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Aggregate.cs:line 118

Как я могу заставить его работать так, чтобы ToListAsync возвращал CustomType<T, K> при работе LINQ to SQL (то есть построено одно выражение SQL)?

Что я пробовал

Я пытался сделать CustomType a class, но затем, по какой-то причине, LINQ to SQL не удается сделать какединственное выражение SQL для selectExpression, поскольку пользовательский тип является class.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...