views:

185

answers:

2

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 lamba functions like that within template classes where no class-specific information is going to be available?

+1  A: 

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));
    }
}
alun
Thanks, +1. Although it works, given that the point of a generic repository template is simplicity and minimising redundant code, I'm hoping there's an answer that doesn't involve needing to make all my entity classes inherit from some GenericWithID class.
FerretallicA
I wasn't aware of dynamic before your answer. Too bad I can't give 2 votes - one for the answer, one for learning something new.
FerretallicA
+1  A: 

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
{
Stef
While the accepted answer for this question solved my problem at the time, I have actually used the approach you've mentioned more recently and prefer it.
FerretallicA