3
votes

I am trying to write a generic one-size-fits-most repository pattern template class for an Entity Framework-based project I'm currently working on. The (heavily simplified) interface is:

internal interface IRepository<T> where T : class
{
  T GetByID(int id);
  IEnumerable<T> GetAll();
  IEnumerable<T> Query(Func<T, bool> filter);
}

GetByID is proving to be the killer. In the implementation:

public class Repository<T> : IRepository<T>,IUnitOfWork<T> where T : class
{
  // etc...
  public T GetByID(int id)
  {
    return this.ObjectSet.Single<T>(t=>t.ID == id);
  }

t=>t.ID == id is the particular bit I'm struggling with. Is it even possible to write lambda functions like that within template classes where no class-specific information is going to be available?

2
While I can do something like || public T GetSingle(<Func T,bool> filter) || I'd really prefer a simpler GetByID if possible given that every repository-bound class will, as a firm rule, have an ID property. - nathanchere
So far the closest I have to a solution is Return Query(Function(x) CType(x, Object).ID = ID) where Query is a wrapper around the datacontext.Where(filter). - nathanchere

2 Answers

4
votes

I've defined a interface:

public interface IIdEntity
{
    long Id { get; set; }
}


And modified the t4 template which generates my POCO classes so that every class must implement the public interface IIdEntity interface.

Like this:

using System.Diagnostics.CodeAnalysis;
public partial class User : IIdEntity
{
    public virtual long Id
    {
        get;
        set;
    }

With this modification I can write a generic GetById(long id) like:

public T GetById(long id)
{
    return Single(e => e.Id == id);
}

The IRepository is defined as follows:

/// <summary>
/// Abstract Base class which implements IDataRepository interface.
/// </summary>
/// <typeparam name="T">A POCO entity</typeparam>
public abstract class DataRepository<T> : IDataRepository<T>
    where T : class, IIdEntity
{
2
votes

You could just create a small interface containing the Id-property and have T be constrained to types that implement it.

EDIT: Based on the comment, if you accept the fact that the compiler wont be helping you ensure that the Id property actually exists you might be able to do something like this:

public class Repo<T> where T : class
{
    private IEnumerable<T> All()
    {
        throw new NotImplementedException();
    }

    private bool FilterOnId(dynamic input, int id)
    {
        return input.Id == id;
    }

    public T GetById(int id)
    {
        return this.All().Single(t => FilterOnId(t, id));
    }
}