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;
}
}
}
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?
TEntTyp
? Expression<Func<TEntTyp, bool>> query
?Thanks and regards
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.