There are a few repository implementations out there in C#. Rhino Commons and S#harp Architecture, among some other one listed on codeplex.
I’ve got my own as well that is part of the CommonLibrary.NET. See the repository example here http://commonlibrarynet.codeplex.com/documentation.
3 Mistakes with Repository Implementations
1. Non-Generic CRUD names
public class BlogPostRepository
public void CreateBlogPost(Post post)...
public void UpdateBlogPost(Post post)...
public void DeleteBlogPost(Post post)
public class BlogPostRepository : IRepository(Post)
public void Create(Post post)...
public void Update(Post post)...
public void Delete(Post post)
Now the 2nd approach is much better and has the following benefits:
- Allows you to extend from a common IRepository class that contains generics based Create,Update,Delete and other methods.
- Provides for more consistency. All your repositories look and behave the same.
- Allows for dynamically creating entities without knowing the type. What I mean by this is that you can populate either a Post or Event object( both of which have their own repositories ) and through some reflection, you can call .Create on the appropriate repository
Create your repository to be even more generic
public class Repository<T> where T: class
public void Delete(int id)…
public void Get(int id)…
public class BlogPostRepository : Repository<BlogPost>
public void Create(T entity)…
public void Update(T entity)…
2. Not using a IQuery for flexible queries
The second method involves having multiple FindXXX methods.
public IList(Event) FindByNameAndGroup( string eventName, string group )...
public IList(Event) FindByOwner( string owner )...
This can easily get out hand.
Instead the following can be done:
public IList(Event) Find( Query query )...
// The caller would use it like so.
public static void main(string args)
repository.Find( Query.New().Where( e => e.Name ).Is( "asp.net" ).And( e => e.Group ).Is( "web" );
Now the second approach will let you handle many different queries. In this example, I’m using a combination of Expression Tree’s and Fluent API to get the Query syntax. This approach is used in the CommonLibrary.net Repository implementation. You can also create helper methods above the repository layer as in example 1 and then delegate to the repo.Find(Query) method on the repository instead of creating multiple FindXXX methods in the repository.
Note: You can also use C#’s Expression Tree purely to accomplish the same effect, for example in Entity Frameworks Find(Expression exp ) methods.
One step further
Now with C# 4.0 dynamic and Expando Object. You can possibly build dynamic find/search method using a ruby rails like style.
1. FindByNameAndOwner is a dynamic method on an expando object.
2. You get the fields to search for using the name of the method ( Name, and Owner) and use the parameters for those variables.
3. You get the condition from the name of the method. ( “NameAndOwner” )
3. Audit fields
Finally, the last problem that I see, is that each entity that is persisted by a repository should have the following audit fields.