Linq and derived entities

Posts   
 
    
rossmcw
User
Posts: 28
Joined: 27-Mar-2008
# Posted on: 26-Jun-2008 07:50:50   

Hi,

It seems a standard LinqMetaData maps directly to EntityNameEntity, which I understand as you dont really want queries including custom entity attributes etc. So when you execute your query it populates EntityNameEntity objects rather than MyEntityNameEntity objects, which means I cant even cast them to MyEntityNameEntity objects as I get a runtime error.

Is it possible to either have the execution return a collection of derived entities directly or to at least populate them at a lower level when they are fetched from the database, so they can be cast?

Hope this makes sense,

Thanks, Ross

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39872
Joined: 17-Aug-2003
# Posted on: 26-Jun-2008 10:02:06   

It's an oversight by us. flushed

When you choose the 2-class approach in adapter, you should be able to query the derived entities and get the derived entities back. We're currently looking into how we're going to fix this (likely through a template addition).

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39872
Joined: 17-Aug-2003
# Posted on: 26-Jun-2008 12:24:37   

I got very far, but then I ran into a bug in the C# compiler. Imagine this query: ILLBLGenProQuery q = (ILLBLGenProQuery)(from c in metaData.Customer select c.Orders);

(Also goes wrong with prefetch paths, the point is the usage of a Related collection in the query, here 'Orders').

'c' is of type MyCustomerEntity, and c.Orders is defined in 'CustomerEntity', but overriden in MyCustomerEntity and a different attribute is applied.

However, the expression tree contains the PropertyInfo of CustomerEntity.Orders, not MyCustomerEntity.Orders. This is shown also in the reflector code of the compiled code:

ParameterExpression CS$0$0000;
LinqMetaData metaData = new LinqMetaData(adapter);
ILLBLGenProQuery q = (ILLBLGenProQuery) metaData.Customer.Select<MyCustomerEntity, EntityCollection<OrderEntity>>(Expression.Lambda<Func<MyCustomerEntity, EntityCollection<OrderEntity>>>(Expression.Property(CS$0$0000 = Expression.Parameter(typeof(MyCustomerEntity), "c"), (MethodInfo) methodof(CustomerEntity.get_Orders)), new ParameterExpression[] { CS$0$0000 }));

Here, you see that it does a methodof on the CustomerEntity type, which is wrong, as the type of 'c' is MyCustomerEntity.

This kind of sucks, as I now can't determine the type of the entity inside the collection, and the linq query can't be parsed.

I'll mail microsoft about this, and have to wait for that reply. I can't add support for two-class scenario in adapter for linq otherwise...

(edit) there might be a hack around this, with an own reflection call on the member, I'll try that and see if I can determine the attribute that way. The MS 'it's a bug' route isn't useful anyway...

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39872
Joined: 17-Aug-2003
# Posted on: 26-Jun-2008 14:16:30   

Ok, I managed to work around it with a simple GetProperty() call on the right type simple_smile , and I now have working code. I'll now convert it into templates / template changes and will check in the LinqSupportClasses update. Unfortunately, you'll require new templates + an updated linq provider to get things working, though missing one update won't break the compile, it just won't work (but it won't work now also, so that's not a step backwards wink ).

I'll attach new goods when they're done.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39872
Joined: 17-Aug-2003
# Posted on: 26-Jun-2008 17:46:59   

I've attached the new templates and the linq provider which works around the issue in the C# compiler.

Frans Bouma | Lead developer LLBLGen Pro
rossmcw
User
Posts: 28
Joined: 27-Mar-2008
# Posted on: 27-Jun-2008 01:08:10   

Thanks Frans,

I have rebuilt everything with the new linq provider and templates, but I cant seem to work out how to use it. If I do the usual 'from o in metadata.orders select o' it still returns OrderEntity and if I try to cast it to MyOrderEntity it still get the same unable to case runtime error.

Do you have to use a slightly different syntax to use derived entities? Otherwise how would it know to populate the derived classes rather than the plain entity classes. I will go through stuff carefully and make sure I am not missing anything.

Apologies in advance if I am doing something stupid or stupidly failing to do something...

Ross

rossmcw
User
Posts: 28
Joined: 27-Mar-2008
# Posted on: 27-Jun-2008 01:22:22   

Also, when working with generic prefetches and derived entities in Linq, would you say '.Prefetch<MyOrderEntity>' or would you say '.Prefetch<OrderEntity>' and it would just know somehow?

Thanks Ross

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39872
Joined: 17-Aug-2003
# Posted on: 27-Jun-2008 09:33:48   

rossmcw wrote:

Thanks Frans,

I have rebuilt everything with the new linq provider and templates, but I cant seem to work out how to use it. If I do the usual 'from o in metadata.orders select o' it still returns OrderEntity and if I try to cast it to MyOrderEntity it still get the same unable to case runtime error.

Do you have to use a slightly different syntax to use derived entities? Otherwise how would it know to populate the derived classes rather than the plain entity classes. I will go through stuff carefully and make sure I am not missing anything.

Apologies in advance if I am doing something stupid or stupidly failing to do something...

Ross

If you use a modified preset for the adapter - two-class scenario, you've to update the LinqMetaData generation task to use the derived entity template (see the updated preset). Also, be sure all code is updated after generating, and that you use the linqsupportclasses dll I included.

About the prefetch path: you should specify the type you want to fetch.

Frans Bouma | Lead developer LLBLGen Pro