Reputation: 4280
I'm implementing an inheritance scenario with Entity Framework 6. Inheritance only exists on DTO level, i.e. i have two classes Foo
and Bar : Foo
,
I have first method that selects an IQueryable<Foo>
and then several methods that select additional properties for specific inheriting classes like Bar.
Normally, I would have code like
from foo in SelectFoo()
join barAdditionalProps in .....
select new Bar{
Id = foo.Id,
Description = foo.Description,
Baz = barAdditionalProps.Baz}
which would give a nice single SQL query as a result.
This, unfortunately, means that all properties from foo will have to be copied during second projection (first one is inside SelectFoo
). In real life code that would mean 20+ properties copied in every method using SelectFoo
.
I would like to do something like this (code is prepared in LINQPad, assume this
== EFContext):
void Main()
{
(from barBase in SelectT<Bar>()
join field in this.Fields on barBase.Id equals field.ProductId
let _1 = barBase.Baz = field.Baz // this part fails with exception
// An expression tree may not contain an assigment operator
select barBase)
.First()
.Dump();
}
public IQueryable<T> SelectT<T>() where T : Foo, new()
{
return this
.Products
.Select(x => new T
{
Id = x.Id,
Description = x.Description
});
}
public class Foo
{
public string Description {get;set;}
public int Id {get;set;}
}
public class Bar : Foo
{
public int Baz {get;set;}
}
Receiving the exception described above, I'm looking for a way to make this work or any other solution that would allow me not to copy all base class properties during second projection.
Upvotes: 1
Views: 630
Reputation: 4280
Since no existing tools were up to the job, I wrote my own library that uses expression tree modification to project baseclass dto in subclass dto automatically.
Now instead of this
IQueryable<BaseDto> baseQuery = GetBaseQuery();
IQueryable<SubclassDto> query = from baseDto in baseQuery
let moreData = DataContext.vMoreData.FirstOrDefault(x => x.Id == baseDto.Id)
select new SubclassDto()
{
NewProp1 = moreData.Foo,
NewProp2 = moreData.Baz,
OldProp1 = moreData.SomeOverridingData,
OldProp2 = baseDto.OldProp2,
OldProp3 = baseDto.OldProp3,
OldProp4 = baseDto.OldProp4,
//... 20 more projections from BaseDto to SubclassDto
};
We have this
IQueryable<BaseDto> baseQuery = GetBaseQuery();
IQueryable<SubclassDto> query = from baseDto in baseQuery
let moreData = DataContext.vMoreData.FirstOrDefault(x => x.Id == baseDto.Id)
select baseDto.AutoProjectInto(() => new SubclassDto()
{
NewProp1 = moreData.Foo,
NewProp2 = moreData.Baz,
OldProp1 = moreData.SomeOverridingData
});
IQueryable<SubclassDto> activateQuery = query.ActivateAutoProjects();
And all properties that were not bound by the SubclassDto initialization are projected from baseDto automatically.
Library is available via Github https://github.com/IKoshelev/Linq.AutoProject and NuGet https://www.nuget.org/packages/Linq.AutoProject
Upvotes: 1