title: Best way to implement Repository Pattern?
body: <p>I've been exploring BDD/DDD and as a consequence trying to come up with a proper implementation of the Repository pattern. So far, it's been hard to find a consensus over the best way to implement this. I've tried to boil it down to the following variations, but I'm unsure which is the best approach.</p>
  
  <p>For reference I'm building an ASP.MVC application with NHibernate as a back-end.</p>
  
  <pre><code>public interface IRepository&lt;T&gt; {
          // 1) Thin facade over LINQ
          T GetById(int id);
          void Add(T entity);
          void Update(T entity);
          void Remove(T entity);
          IQueryable&lt;T&gt; Find();
          // or possibly even
          T Get(Expression&lt;Func&lt;T, bool&gt;&gt; query);
          List&lt;T&gt; Find(Expression&lt;Func&lt;T, bool&gt;&gt; query);
  }
  
  public interface IRepository&lt;T&gt; {
          // 2) Custom methods for each query
          T GetById(int id);
          void Add(T entity);
          void Update(T entity);
          void Remove(T entity);
          IList&lt;T&gt; FindAll();
          IList&lt;T&gt; FindBySku(string sku);
          IList&lt;T&gt; FindByName(string name);
          IList&lt;T&gt; FindByPrice(decimal price);
          // ... and so on
  }
  
  public interface IRepository&lt;T&gt; {
          // 3) Wrap NHibernate Criteria in Spec pattern
          void Add(T entity);
          void Update(T entity);
          void Remove(T entity);
          IList&lt;T&gt; FindAll();
          IList&lt;T&gt; FindBySpec(ISpecification&lt;T&gt; specification);
          T GetById(int id);
  }
  
  
  public interface IRepository&lt;T&gt; {
          // 4) Expose NHibernate Criteria directly
          T GetById(int id);
          void Add(T entity);
          void Update(T entity);
          void Remove(T entity);
          IList&lt;T&gt; FindAll();
          IList&lt;T&gt; Find(ICriteria criteria);
          // .. or possibly
          IList&lt;T&gt; Find(HQL stuff);
  }
  </code></pre>
  
  <p>My initial thoughts are that </p>
  
  <p>1) is great from an efficiency point of view, but I may get into trouble as things get more complicated. </p>
  
  <p>2) seems very tedious and could end up with a very crowded class, but otherwise offers a high degree of separation between my domain logic and data layer which I like.</p>
  
  <p>3) seems difficult up front and more work to write queries, but limits cross contamination to just the Specs layer.</p>
  
  <p>4) My least favorite, but possibly most direct implementation and possibly most database efficient for complex queries, though it puts a lot of responsibility on the calling code.</p>