Preben Huybrechts
Preben Huybrechts

Reputation: 6151

Expression.Convert using type that isn't included

So this is the Setup

You have a namespace DAL and a namespace DTO (In a different assembly). Both contain a class Foo. What I was trying to do, is to specify EF includes on a DTO type and convert them to a DAL type.

We have the following collection coming from the front-end:

using DTO;

public class GetFooById : Request
{
    public GetFooById()
    {
        IncludeProperties = new HashSet<Expression<Func<object, object>>>
                    {
                        x  => ((Foo)x).Bar, //DTO.Foo, when debugging is DAL.Foo
                        x => ((Foo)x).Foobars,
                    };
    }
}

We use this collection in another assembly, something like this:

IQueryable<object> query = Context.Foos;

foreach (var expr in request.IncludeProperties)
{
        query = query.Include(expr);
}

var foo = query.First(x => x.Id == request.Id);

The strange part is, this code is compiling and executing, but the included properties are null. When I'm debugging and hover over this part: x => ((Foo)x).Bar The debugger says Foo is of type: DAL.Foo instead of the included DTO.Foo.

Is this because the expression is compiled in a file where we don't have an include to DTO, but we have an include to DAL? Isn't this a bug in c# ?

Is this expected behavior in C# ?

Project framework is 4.0, but i'm compiling with 4.5 installed.

Upvotes: 0

Views: 96

Answers (2)

user743382
user743382

Reputation:

This is not caused by C#. You're ignoring the result of query.Include(expr);, so the Include expression does not actually get applied anyway. As long as it remains unused, it cannot cause problems: even in regular C# code (without expression trees), if you've got an object of type A, then casting it to a completely distinct type B using (B)(object)a would obviously not work, but this would be detected at runtime, so only if the code actually gets called.

Also, Entity Framework does not currently support multiple types with the same name, as far as I am aware. It looks up types by name, and DAL.Foo and DTO.Foo have the same name. The type that EF knows about is the type that it ends up using. You should not rely on this.

Upvotes: 1

Ehsan
Ehsan

Reputation: 32729

AS DAL.Foo is closer(in current assembly) than DTO.Foo (in an included assembly) hence the compiler picks it up first. It is expected and consistent behaviour, not a bug. You need to specify the name explicitly so, change this

x  => ((Foo)x).Bar, 

to

 x  => ((DTO.Foo)x).Bar, 

Upvotes: 0

Related Questions