Reputation: 22595
I have a method in my generic repository that returns an IQueryable<T>
:
public virtual IQueryable<T> All
{
get
{
DbSet<T> set = Context.Set<T>();
if (typeof(T).IsSubclassOf(typeof(OrganisationDependent)))
return set.AsEnumerable()
.Cast<OrganisationDependent>()
.Where(x => x.OrganisationID == CurrentOrganisationID)
.AsQueryable()
.Cast<T>();
return set;
}
}
The reason for the if statement is that most, but not all of my tables have an OrganisationID
and I want to ensure that a user only sees data for the organisation they belong to. The above code works but in order to make it work I had to add the AsEnumerable()
to pull the data into memory. Without it I get the error message
"Unable to cast the type 'Models.xxx' to type 'Models.OrganisationDependent'. LINQ to Entities only supports casting EDM primitive or enumeration types"
All my entities directly inherit either ModelBase
or OrganisationDependent
:
public abstract class OrganisationDependent : ModelBase
{
public int OrganisationID { get; set; }
public virtual Organisation Organisation { get; set; }
}
public abstract class ModelBase
{
public int ID { get; set; }
}
Is there a way that I can overcome this restriction so that when the type is a sub class of OrganisationDependent
, I filter on OrganisationID
without having to pull the query into memory?
Upvotes: 3
Views: 1925
Reputation: 31218
The simplest option is probably to use the LINQ Expressions API to build a filter expression dynamically:
private static readonly PropertyInfo _organizationIdProperty
= typeof(OrganisationDependent).GetProperty("OrganisationID");
private static Expression<Func<T, bool>> FilterByOrganization<T>(int organizationId)
{
var item = Expression.Parameter(typeof(T), "item");
var propertyValue = Expression.Property(item, _organizationIdProperty);
var body = Expression.Equal(propertyValue, Expression.Constant(organizationId));
return Expression.Lambda<Func<T, bool>>(body, item);
}
public virtual IQueryable<T> All
{
get
{
IQueryable<T> set = Context.Set<T>();
if (typeof(T).IsSubclassOf(typeof(OrganisationDependent)))
{
var filter = FilterByOrganization<T>(CurrentOrganisationID);
set = set.Where(filter);
}
return set;
}
}
Upvotes: 4