I have two Entity Framework 5 Get() methods that perform (i) a single entity get by ID, and (ii) a single entity get via a filter with any eager loading bolted on. See below for the code:
internal readonly FallenNovaContext Context;
private readonly DbSet<TEntity> _dbSet;
internal GenericRepository(FallenNovaContext context)
{
Context = context;
_dbSet = context.Set<TEntity>();
}
// (i) Get by ID.
public TEntity GetById(int id)
{
return _dbSet.Find(id);
}
// (ii) Get by filter and optional eager loading includes.
public TEntity Get(
Expression<Func<TEntity, bool>> filter = null,
IEnumerable<string> includePaths = null)
{
IQueryable<TEntity> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
if (includePaths != null)
{
query = includePaths.Aggregate(query, (current, includePath) => current.Include(includePath));
}
return query.SingleOrDefault();
}
All of which works fine now what I'm finding as my application grows is I'm writing a lot of non-generic methods that need a mix of both - more specifically I want a generic get by ID and also be able to eager load related entities.
So the method signature would look something like this:
public TEntity GetById(
int id,
IEnumerable<string> includePaths)
{
// ???
}
Which I could call like this:
User user = UnitOfWork.UserRepository.GetById(117, new List<string>() { "UserRole", "UserStatus" });
Or like this:
Car car = UnitOfWork.CarRepository.GetById(51, new List<string>() { "Make", "Model", "Tyres" });
Any help on the suggestions of how I use Entity Framework 5 to code the logic for the TEntity GetById(int id, IEnumerable includePaths) method would be appreciated.
First, write a base class for entities, which defines the primary key field. Something like the following may work:
public abstract class BaseEntity
{
public int Id {get;set;}
}
Then, write a base class for your repositories; define all generic methods in this base repository. Let this repository have a generic parameter of entity type:
public class RepositoryBase<TEntity> where TEntity : BaseEntity
{
public TEntity GetById(
int id,
params Expression<Func<TEntity, object>>[] includeList)
{
TEntity entity = null;
ObjectQuery<TEntity> itemWithIncludes = context.Set<TEntity>() as ObjectQuery<TEntity>;
foreach (Expression<Func<TEntity, object>> path in includeList)
{
itemWithIncludes = ((IQueryable)itemWithIncludes.Include(path)) as ObjectQuery<T>;
}
IQueryable<TEntity> items = itemWithIncludes.AsQueryable<TEntity>();
entity = items.Where(p => p.Id == id).SingleOrDefault();
return entity;
}
}
Update: @Bern asked whether there is any other way to find primary key than declaring a base class. The following questions refer to this problem.
Entity Framework 4: How to find the primary key?
Entity Framework code first. Find primary key
On the otherhand I do not know if there is any other way in EF 5.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With