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
.