Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter with multiple derived classes with Code-first Entity Framework

Lets say I have a User with 2 derived entities Student, Teacher. I used the TPH method, so I actually have no property at all in my classes to tell me who is a teacher or not.

I have 2 booleans that should allow me to load either student or teacher such as this:

//IQueryable<User>
var query = userRepository.GetUsers();

//Type filtering
if (searchModel.IsStudent)
{
    query = query.OfType<Student>();
}
if (searchModel.IsTeacher)
{
    query = query.OfType<Teacher>();
}

When this tries to evaluate, I get this error when both are true:

DbIsOfExpression requires an expression argument with a polymorphic result type that is compatible with the type argument.

I already looked at some answers here on SO but they are geared towards 1 type of filtering.

I would then like to do something like this (rough coding):

if(query.ToList().FirstOrDefault() is Student)
{
     print "student";
}

The mapping:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
                    .Map<Teacher>(m => m.Requires("UserType").HasValue("Teach"))
                    .Map<Student>(m => m.Requires("UserType").HasValue("Stu"))
                    .Map<Staff>(m => m.Requires("UserType").HasValue("Staff"));
    }
like image 813
Shawn Mclean Avatar asked Oct 26 '11 00:10

Shawn Mclean


2 Answers

Try this one. It works at least for EF 5.

IQueryable<User> Filter(this IQueryable<User> query, 
    bool includeTeacher, bool includeStudent)
{

  return query.Where(x => includeTeacher && x is Teacher
                || includeStudent && x is Student);
}
like image 98
mt_serg Avatar answered Oct 12 '22 10:10

mt_serg


This is ugly but it will work for what you need:

if (searchModel.IsStudent && searchModel.IsTeacher) 
{
    var result = context.Users.OfType<Teacher>()
                        .Cast<User>()
                        .Union(context.Users.OfType<Student>());
}

And It will run on one query!! :)

like image 33
marianosz Avatar answered Oct 12 '22 10:10

marianosz