3

In general, If I create an extension method that acts on an entity:

public static MyEntity Foo(this MyEntity entity)
{
  // do something to the entity
}

One cannot directly use this in a projection from Linq-To-Entities such as follows:

var result = myContext.MyEntities.Select(x=> x.Foo());

Doing so yields an error such as:

System.NotSupportedException: LINQ to Entities does not recognize the method 'Foo(MyEntity)' method, and this method cannot be translated into a store expression.

I fully understand why this error occurs. My question is this: If I can provide an implementation of Foo that uses an expression tree, is there some way that I can add Foo to the operations that LINQ-to-entities understands? And if so - how?


Note: I can certainly convert it to a list like this:

var result = myContext.MyEntities.ToList().Select(x=> x.Foo());

And it doesn't error. But I no longer have an IQueryable. I have an IEnumerable. If I were to use it like this:

var result = myContext.MyEntities.ToList().Select(x=> x.Foo()).First();

I would end up fetching ALL entities before taking the top one and discarding the rest - which would be horrible for performance.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • 1
    You can write your own IQueryProvider, wrap EF's query provider, recognize your expression that calls Foo, and feed EF a chain of equivalent expressions that it can translate to the language of the backing store (e.g. SQL). But that's not much fun, and it's not universal. What does `Foo` do, anyway? – Sergey Kalinichenko Dec 10 '11 at 02:56
  • It doesn't really matter what it does, that's why I just called it Foo. I have a few different needs for stuff like this and was really just looking for the hooks. I like your idea about wrapping the EF query provider. Can you provide an example? Thanks! – Matt Johnson-Pint Dec 10 '11 at 05:15
  • 1
    See: [How to wrap Entity Framework to intercept the LINQ expression just before execution?](http://stackoverflow.com/questions/1839901/how-to-wrap-entity-framework-to-intercept-the-linq-expression-just-before-execut) – Ani Dec 10 '11 at 06:00
  • @MattJohnson What `Foo` does matters a lot, as your ability to push the logic into the underlying data store depends on it. Ultimately your implementation would either have `Foo`'s logic executed in RDBMS, or pull everything into memory and run `Foo` inside CLR (essentially, resorting to the same code path as with `ToLost` in your example). However, general, EF gives you lots of very useful extension points that you should consider before going for your own IQueryProvider wrapper. – Sergey Kalinichenko Dec 10 '11 at 14:10
  • @dasblinkenlight I see what you are getting at. Can you elaborate on other extension points that might be more useful? Basically, I need to implement something like the .Include method, but I need to change the behavior of the SQL join that EF creates. – Matt Johnson-Pint Dec 11 '11 at 22:36
  • @Ani I saw this, but I'm not sure how it helps me. How could I implement Foo? Following the example in that link, I don't understand why their QueryTranslator.Include is any different than just using the original .Include method directly. – Matt Johnson-Pint Dec 11 '11 at 22:38
  • @dasblinkenlight Disregard my comment about changing the behavior of the .Include method. I restructured my data model so that this is unneccessary. EF seems to work best if there are no complex behaviors on the joins. – Matt Johnson-Pint Dec 14 '11 at 18:52

1 Answers1

2

Use LINQKit project, but instead of your method foo, You will be obliged to write expression tree which is equivalent.

Mic
  • 810
  • 10
  • 15
  • Neat library - but all the examples show adding criteria to the where clause. Can you provide an example that performs a projection in the select statement like my Foo would need to do? – Matt Johnson-Pint Dec 13 '11 at 18:00
  • 1
    Try this: Expression> test = (x) => x; var result = context.Collection_Of_TEntity.AsExpandable().Select(x=> test.Invoke(x)).ToList(); – Mic Dec 14 '11 at 11:20
  • This pretty much does what I originally asked. Thanks! – Matt Johnson-Pint Dec 14 '11 at 18:52