views:

1136

answers:

1

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 then 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
}
+1  A: 

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 For {
    get {
      return Container.Resolve>();
    }
  }
}

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.

Squirrel