Zaimplementowałam podstawowego (naiwnego?) Dostawcę LINQ, który działa dobrze dla moich celów, ale jest kilka dziwactw, którymi chciałbym się zająć, ale nie jestem pewien jak. Na przykład:Jak sprawić, aby LINQ-to-Object obsłużyło projekcje?
// performing projection with Linq-to-Objects, since Linq-to-Sage won't handle this:
var vendorCodes = context.Vendors.ToList().Select(e => e.Key);
Moja implementacja IQueryProvider
miał CreateQuery<TResult>
realizacja wygląda tak:
public IQueryable<TResult> CreateQuery<TResult>(Expression expression)
{
return (IQueryable<TResult>)Activator
.CreateInstance(typeof(ViewSet<>)
.MakeGenericType(elementType), _view, this, expression, _context);
}
Oczywiście dławiki gdy Expression
jest MethodCallExpression
i TResult
jest string
, więc pomyślałem, ja bym wykonaj rzecz:
public IQueryable<TResult> CreateQuery<TResult>(Expression expression)
{
var elementType = TypeSystem.GetElementType(expression.Type);
if (elementType == typeof(EntityBase))
{
Debug.Assert(elementType == typeof(TResult));
return (IQueryable<TResult>)Activator.CreateInstance(typeof(ViewSet<>).MakeGenericType(elementType), _view, this, expression, _context);
}
var methodCallExpression = expression as MethodCallExpression;
if(methodCallExpression != null && methodCallExpression.Method.Name == "Select")
{
return (IQueryable<TResult>)Execute(methodCallExpression);
}
throw new NotSupportedException(string.Format("Expression '{0}' is not supported by this provider.", expression));
}
Tak więc po uruchomieniu kończę w moim przeciążeniu , które przełącza najbardziej wewnętrzną nazwę metody wyrażenia filtru i wykonuje faktyczne wywołania w bazowym interfejsie API.
Teraz, w tym wypadku jestem zdaniu wyraz połączenia Select
metoda, więc wyrażenie filtr jest null
i mój switch
blok zostanie pominięty - co jest w porządku - gdzie utknąłem na jest tutaj:
var method = expression as MethodCallExpression;
if (method != null && method.Method.Name == "Select")
{
// handle projections
var returnType = method.Type.GenericTypeArguments[0];
var expType = typeof (Func<,>).MakeGenericType(typeof (T), returnType);
var body = method.Arguments[1] as Expression<Func<T,object>>;
if (body != null)
{
// body is null here because it should be as Expression<Func<T,expType>>
var compiled = body.Compile();
return viewSet.Select(string.Empty).AsEnumerable().Select(compiled);
}
}
Co muszę zrobić, aby mój MethodCallExpression
był w stanie przekazać go do metody LINQ-to-Object 'Select
? Czy podchodzę do tego poprawnie?
Możesz pobrać Expression z przychodzącej metody Select, a następnie przekazać ją do ViewSet Select lub skompilować jako Func i przekazać tam. Więc po prostu wyślesz ponownie projekcję do swojego zestawu widoków. –
@SergeyLitvinov ok ... więc w jaki sposób uzyskać 'Expression>' z tego 'MethodCallExpression'? –
Również, jeśli nie mam uchwytu na typ powrotu 'Func', jak mogę rzucić go do prawidłowego' Wyrażenie 'tak, aby móc uzyskać dostęp do metody' Kompilacja' i utrzymać rzeczy mocno wpisane aby ".Select (ConverExpression)" mógł działać? –