Question

I am getting ready to start a new asp.net web project, and I am going to LINQ-to-SQL. I have done a little bit of work getting my data layer setup using some info I found by Mike Hadlow that uses an Interface and generics to create a Repository for each table in the database. I thought this was an interesting approach at first. However, now I think it might make more sense to create a base Repository class and inherit from it to create a TableNameRepository class for the tables I need to access.

Which approach will be allow me to add functionality specific to a Table in a clean testable way? Here is my Repository implementation for reference.

public class Repository<T> : IRepository<T> where T : class, new()
{
    protected IDataConnection _dcnf;

    public Repository()
    {
        _dcnf = new DataConnectionFactory() as IDataConnection;
    }

    // Constructor injection for dependency on DataContext 
    // to actually connect to a database
    public Repository(IDataConnection dc)
    {
        _dcnf = dc;
    }

    /// <summary>
    /// Return all instances of type T.
    /// </summary>
    /// <returns>IEnumerable<T></returns>
    public virtual IEnumerable<T> GetAll()
    {
        return GetTable;
    }

    public virtual T GetById(int id)
    {
        var itemParam = Expression.Parameter(typeof(T), "item");
        var whereExp = Expression.Lambda<Func<T, bool>>
            (
                Expression.Equal(
                    Expression.Property(itemParam, PrimaryKeyName),
                    Expression.Constant(id)
                ), new ParameterExpression[] { itemParam }
            );
        return _dcnf.Context.GetTable<T>().Where(whereExp).Single();
    }

    /// <summary>
    /// Return all instances of type T that match the expression exp.
    /// </summary>
    /// <param name="exp"></param>
    /// <returns>IEnumerable<T></returns>
    public virtual IEnumerable<T> FindByExp(Func<T, bool> exp)
    {
        return GetTable.Where<T>(exp);
    }

    /// <summary>See IRepository.</summary>
    /// <param name="exp"></param><returns></returns>
    public virtual T Single(Func<T, bool> exp)
    {
        return GetTable.Single(exp);
    }

    /// <summary>See IRepository.</summary>
    /// <param name="entity"></param>
    public virtual void MarkForDeletion(T entity)
    {
        _dcnf.Context.GetTable<T>().DeleteOnSubmit(entity);
    }

    /// <summary>
    /// Create a new instance of type T.
    /// </summary>
    /// <returns>T</returns>
    public virtual T Create()
    {
        //T entity = Activator.CreateInstance<T>();
        T entity = new T();
        GetTable.InsertOnSubmit(entity);
        return entity;
    }

    /// <summary>See IRepository.</summary>
    public virtual void SaveAll()
    {
        _dcnf.SaveAll();
    }

    #region Properties
    private string PrimaryKeyName
    {
        get { return TableMetadata.RowType.IdentityMembers[0].Name; }
    }

    private System.Data.Linq.Table<T> GetTable
    {
        get { return _dcnf.Context.GetTable<T>(); }
    }

    private System.Data.Linq.Mapping.MetaTable TableMetadata
    {
        get { return _dcnf.Context.Mapping.GetTable(typeof(T)); }
    }

    private System.Data.Linq.Mapping.MetaType ClassMetadata
    {
        get { return _dcnf.Context.Mapping.GetMetaType(typeof(T)); }
    }
    #endregion
}
Was it helpful?

Solution

I'd be tempted to suggest that whether you use concrete types or not shouldn't matter, as if your using dependency injection (castle?) to create the repositories (so you can wrap them with different caches etc) then your codebase will be none the wiser whichever way you've done it.

Then just ask your DI for a repository. E.g. for castle:

public class Home {
  public static IRepository<T> For<T> {
    get {
      return Container.Resolve<IRepository<T>>();
    }
  }
}

Personally, I'd not bottom out the types until you find a need to.

I guess the other half of your question is whether you can easily provide an in memory implementation of IRepository for testing and caching purposes. For this I would watch out as linq-to-objects can be slow and you might find something like http://www.codeplex.com/i4o useful.

OTHER TIPS

You should not create a repository for every table.
Instead, you should create a repository for every 'entity root' (or aggregate root) that exists in your domain model. You can learn more about the pattern and see a working example here:

http://deviq.com/repository-pattern/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top