Reputation: 21766
I have a LINQ to entities model with Table Per Hierarchy inheritance. I have a query over the base type, and I want to do specific type-dependent logic. For example:
IQueryable<BaseType> base = ...
// this works fine
var result = base.Select(b => b is DerivedType1 ? 1 : 2).ToList();
// this doesn't compile to SQL
var result2 = base.Select(b => b is DerivedType1 ? ((DerivedType1)b).DerivedProperty : null).ToList();
Is there any way to do something like this without processing IQueryables of each derived type separately:
// I'd rather not do this:
var resultA = base.OfType<DerivedType1>().Select(d => d.DerivedProperty);
var resultB = base.OfType<DerivedType2>().Select(d => default(int?));
var result = resultA.Concat(resultB).ToList();
Upvotes: 25
Views: 13389
Reputation: 3952
You can use EntityFramework.Extended to improve the performance of the query instead of doing 2 round trips to DB.
var resultA = base.OfType<DerivedType1>().Select(d => d.DerivedProperty).Future();
var resultB = base.OfType<DerivedType2>().Select(d => default(int?)).Future();
var result = resultA.Concat(resultB).ToList();
In this case only one round trip to bd is executed. This framework is very useful for many other things int EF
Upvotes: 1
Reputation: 177133
Direct casting to an entity type like (DerivedType1)b
isn't supported with LINQ-to-Entities but the as
operator (b as DerivedType1
) is, hence you could try:
var result2 = base
.Select(b => b is DerivedType1
? (b as DerivedType1).DerivedProperty
: null)
.ToList();
Upvotes: 32
Reputation: 172
OfType<DerivedType1>()
will return an IEnumerable, if possible, try to change to base-type to IEnumerable instead of IQueryable, you might en up in some SQL restrictions when using IQueryable.
That is of course if you are not actually quering a database?
Upvotes: 1
Reputation: 2136
Try this, I have never done anything with needing to do this kind of this but this should do it. Also if you use base
, first of all don't because it is a keyword but if you must, use @base
the @ in front of the name denotes that it is not used as a keyword.
var resultA = base.Select(aVar =>
(aVar is DerivedType1) ?
(DerivedType)(((DerivedType1)aVar).DerivedProperty)
:
(DerivedType)(default(int?))
).ToList();
Upvotes: 0
Reputation: 5781
You could have a method on your base type that's overridden in your derived types to provide the relevant property value.
public class MyBaseClass
{
public virtual int GetSomething()
{
throw new NotImplementedException();
}
}
public class MyDerivedClass1 : MyBaseClass
{
public int SomeProperty { get; set; }
public override int GetSomething()
{
return this.SomeProperty;
}
}
public class MyDerivedClass2 : MyBaseClass
{
public int SomeOtherProperty { get; set; }
public override int GetSomething()
{
return this.SomeOtherProperty;
}
}
Then you could:
var result = base.Select(b => b.GetSomething()).ToList();
Upvotes: 0