4

I'm just starting to use LinqKit with EntityFramework 6.0.2 and I have the following question...

Why does this:

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;
}

throw:

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'.

but this:

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;
}

works fine?

kmp
  • 10,535
  • 11
  • 75
  • 125

1 Answers1

4

That's because inside your expression you are accessing a Field. The exception tells you that you are accessing a field.

The expression is not evaluated when you create the query. It is only executed once you execute it. At that point, it will need to resolve the field. A workaround is getting the expression first into a local variable:

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

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

Seeing that you are using this with EntityFramework, what will happen is that your expression will be converted to a SQL query. However, since you are accessing a class inside the expression, it cannot convert this to a SQL statement (how would it do that?). When you have an instance of the expression (with the local variable) you are eliminating this class access and that expression can be converted into SQL.

Kenneth
  • 28,294
  • 6
  • 61
  • 84
  • Thanks for the answer - I have already changed my code to use the local variable approach, but I guess the point of my question was (and would have been better put if I had said this I suppose): why can't it resolve that field at runtime? This library seems just so amazingly clever that perhaps I am expecting too much. – kmp Mar 06 '14 at 12:26
  • Edited my answer with a bit more info – Kenneth Mar 06 '14 at 12:31
  • Thanks for the answer and update - I get it now. The thing that made me think it would be reasonable is that you can do: `private static readonly Expression> SomeCondition = e => e.SomeEnum == MyEnum.Two;` and then `things.First(Program.SomeCondition)` but, of course, there the expression isn't referencing a class field, the entire expression is just added to the expression tree from the field. Still feels a little bit disappointing that I have to do this but then this library is like a present anyway and I shouldn't complain. – kmp Mar 06 '14 at 12:50