Search code examples
c#entity-frameworklinqarchitectureabstraction

Code disentangle - what does query of T do


We have three components: WinForm-Rich-Client, IIS-Webserver using WebApi, entity framework for most of the database queries.

I was given a code base and i am lost. I unterstand that some classes Student are passed dynamically around using TEntityType. I the msdn docs i read that you can use this approach when you do not statically know the type of T.

I am trying to understand the lines below, what they do and if the relations between all the interfaces and abstract classes have any benefits

var students = DbEntityAccess.Query<Students>().ToList();

// the query member from Our.DAL.Interfaces.IEntityAccess 
IQueryable<TEntTyp> 
              Query<TEntTyp>(Expression<Func<TEntTyp, bool>> query)
                  where TEntTyp: class;

DBEntityAccesss

Definition (F12) and implementation for DBEntityAccesss both lead to

namespace Our.Webservice.Controllers
{
   public abstract class SessionBaseController : ApiController
   {
      protected IEntityAccess DbEntityAccess { get; private set; }
   }
}

Sidenote: Visual Studio suggests to rename DbEntityAccess to GetDbEntityAccess

IEntityAccess

The definition (F12) and the implementation (STRG+F12) of IEntityAccess are these

// Definition of SessionBaseController.IEntityAccess
namespace Our.DAL.Interfaces
{
  public interface IEntityAccess
  {
    IQueryable<TEntTyp> 
       Query<TEntTyp>(Expression<Func<TEntTyp, bool>> query)
            where TEntTyp: class;
  }
}


// Implementation of SessionBaseController.IEntityAccess
namespace Our.DAL.Implementations
{
   public class TpdEntities : DbAccess, IEntityAccess
   {
     // TEntityType shortened to TEntTyp 
     public IQueryable<TEntTyp> Query<TEntTyp>() where TEntTyp: class
     {
       return Set<TEntTyp>();
     }
   }
}

Our.DAL.Implementations.TpdEntities

The class Our.DAL.Implementations.TpdEntities is implementing the interface Our.DAL.Interfaces.IEntityAccess (see above) and inherits from DbAccess which is an abstract class that inherits from System.Data.Entity.DbContext

Our.DAL.Implementations.DbAccess

It is unclear what DbAccess contributes.

namespace Our.DAL.Implementations
{
  public abstract class DbAccess : DbContext
  {
      // Constructor
      protected DbAccess()
          : base("name=TPDEntities")
      {
          Configuration.AutoDetectChangesEnabled = false;
      }
  }
}

Questions

How is the first part wired up

  • What does query do, how and when does EF come into play var students = DbEntityAccess.Query<Students>().ToList();

  • What does the part Query<TEntTyp>(Expression<Func<TEntTyp, bool>> query) where TEntTyp: class; do?

  • To me it is unclear what Query does?
  • How does it query the passed T TEntTyp?
  • What does Expression<Func<TEntTyp, bool>> query?

Thanks and regards


Solution

  • So the Implementation of IEntityAccess should not work because it is missing the parameter Expression<Func<TEntTyp, bool>> query it should look like:

    namespace Our.DAL.Implementations
    {
       public class TpdEntities : DbAccess, IEntityAccess
       {
         // TEntityType shortened to TEntTyp 
         public IQueryable<TEntTyp> Query<TEntTyp>(Expression<Func<TEntTyp, bool>> query) 
         where TEntTyp: class
         {
           return Set<TEntTyp>().Where(query);
         }
       }
    }
    

    As it is written now, there is no difference than directly accessing the DbAccess class. If you look at DbAccess it inherits DbContext(Entity Framework) and holds the collections.

    What does query do, how and when does EF come into play var students = DbEntityAccess.Query().ToList();

    So, DbEntityAccess is an interface, but has an implementation of TpdEntities. Assuming that is what is set, is the same as DbAccess.Students.

    What does the part Query<TEntTyp>(Expression<Func<TEntTyp, bool>> query) where TEntTyp: class; do?

    This is the interesting part. You can use a Predicate to filter the collection further. For example, you need only currently registered students. If you try this with DbAccess it would look like:

    var registeredStudents = DbAccess.Students.Where(student => student.IsRegistered);
    

    The Query method does the same thing:

    var registeredStudents = DbEntityAccess.Query(student => student.IsRegistered);    
    

    The student => student.IsRegistered is a predicate Func<Student, bool> that returns a student if they satisfy some condition.

    Why would you want all this abstraction?

    For future extensibility. Let's imagine that this controller is only concerned about currently registered students and will never need past students. the TpdEntities could then be switched for

    namespace Our.DAL.Implementations
    {
       public class CurrentStudentsRepository : DbAccess, IEntityAccess
       {
         // TEntityType shortened to TEntTyp 
         public IQueryable<Student> Query<Student>(Expression<Func<Student, bool>> query) 
         where Student: class
         {
           return Set<Student>().Where(student => student.IsRegistered).Where(query);
         }
       }
    }
    

    Because this returns IQueryable you can then further filter the collection before asking the Database to get the data.

    var students = DbEntityAccess.Query(student => student.FirstName == "Jim");

    will return all currently enrolled students with a first name of Jim in a very readable way.