Почему я получаю InvalidCastException при использовании выражения из статического поля?

Я только начинаю использовать LinqKit с EntityFramework 6.0.2 и у меня следующий вопрос...

Почему это:

public static readonly Expression<Func<MyEnum, string>> ConvertToString = e => 
        e == MyEnum.One
                    ? "one"
                    : e == MyEnum.Two
                        ? "two"
                        : "zero";

private static string GetSomethingElse(IQueryable<EnumTest> things)
{           
    var ret = things
        .AsExpandable()
        .Select(c => Program.ConvertToString.Invoke(c.SomeEnum))
        .First();
    return ret;
}

бросить:

An unhandled exception of type 'System.InvalidCastException' 
    occurred in LinqKit.dll

Additional information: Unable to cast object of type     
    'System.Linq.Expressions.FieldExpression' to type 
    'System.Linq.Expressions.LambdaExpression'.

но это:

private static string GetSomething(IQueryable<EnumTest> things)
{
    Expression<Func<MyEnum, string>> ConvertToString = e => e == MyEnum.One
        ? "one"
        : e == MyEnum.Two
            ? "two"
            : "zero";

    var ret = things
        .AsExpandable()
        .Select(c => ConvertToString.Invoke(c.SomeEnum))
        .First();
    return ret;
}

работает отлично?

1 ответ

Решение

Это потому, что внутри вашего выражения вы получаете доступ к полю. Исключение говорит вам, что вы получаете доступ к полю.

Выражение не оценивается при создании запроса. Это выполняется только после того, как вы выполните его. На этом этапе ему нужно будет разрешить поле. Обходной путь - сначала получить выражение в локальной переменной:

private static string GetSomething(IQueryable<EnumTest> things)
{
    var expression = Program.ConvertToString;

    var ret = things
        .AsExpandable()
        .Select(c => expression.Invoke(c.SomeEnum))
        .First();
    return ret;
}

Видя, что вы используете это с EntityFramework, вы получите то, что ваше выражение будет преобразовано в SQL-запрос. Однако, поскольку вы обращаетесь к классу внутри выражения, он не может преобразовать его в оператор SQL (как он это сделает?). Когда у вас есть экземпляр выражения (с локальной переменной), вы исключаете доступ к этому классу, и это выражение можно преобразовать в SQL.

Другие вопросы по тегам