How I do data-access

Posted by Kenny Eliasson | Posted in , , , , | Posted on 10:04

Over the years I've tested alot of different techniques for getting data from a database in a .NET application.

From the simple ADO.NET wrapper that executes raw sql or SP's and then returning a DataTable to the more specified "Repository" where each entity in my domain had a corresponding Repository for querying the data.

I then discovered ORM's, especially NHibernate and started using it with the "One repository for each entity" approach. This worked great but when my projects grew bigger and bigger the need to create a new Repository for each new entity was to cumbersome (and often the Repository would have an interface, so for each new entity I created 3 new classes).

I later implemented Linq2NHibernate and made it so that the most basic queries (i.e find by name, ordering etc) was made using it. More advanced queries I still shuffled into a entity-specific repository.

My interface at this time looked at this

public interface INHibernateRepository
{
    ICriteria ExecuteCritera(DetachedCriteria criteria);
    IQuery ExecuteCritera(string hql);
    IList ExecuteMultiCriteria(params DetachedCriteria[] criterias);
    void Delete(int id) where ENTITY : DomainObject;
    int Save(ENTITY entity) where ENTITY : DomainObject;
    IQueryable Query() where ENTITY : DomainObject; //Linq2Nhibernate
    ENTITIY Get(int id) where ENTITIY : DomainObject;
}

Pretty basic stuff for querying and fetching by Primary Key.

If i got a entity specific repository i would extend INHibernateRepository like this

public interface QuestionRepository : INHibernateRepository
{
    Question GetLatestInserted();
    //more question specific implementations
}

I then, of course, had implementing classes of these interfaces.

To use it in a MVC application I used Dependency Injection to wire up my controllers.

public class QuestionController(INHibernateRepository repository, IQuestionRepository questionRepository, IUserRepository userRepository /* etc */)
{
}

Some may say that I shouldn't inject repositories directly to my controller, but even if I broke it out to a domain-service, it would still need 3 dependencies.

So instead of using the approach above I have begun using Domain Queries. I've read abit about them before but I was when i read Implementing Domain Queries i realized how it would benefit me.

I started my refactoring spree by adding two new methods on my repository interface

public interface INHibernateRepository : IRepository
{
    IEnumerable Query(IDomainQuery query);
    T FindOne(IDomainQuery domainQuery);
    /* All other methods */
}

I then one by one extracted the more complicated queries to their own query-class.

During this process I didn't encounter a single problem and I could remove all of my entity specific repositories and use _one_ repository for all database calls.

So when I'm writing a query nowadays, I first and foremost try to use Linq, if that doesn't work I create a new query class instead of creating a whole new repository for a single entity.

Comments (3)

  1. What do you have in your IRepository today? Is it just the Save and Delete methods?

  2. In short, yes, Load/Get/Save/Delete and Linq/DomainQuery.

    IEnumerable Query(IDomainQuery query);
    IQueryable Query() where ENTITY : DomainObject;
    T FindOne(IDomainQuery domainQuery);
    ENTITIY Load(int id) where ENTITIY : DomainObject;
    ENTITIY Get(int id) where ENTITIY : DomainObject;
    void Delete(ENTITY entity) where ENTITY : DomainObject;
    void Delete(int id) where ENTITY : DomainObject;
    int Save(ENTITY entity) where ENTITY : DomainObject;

  3. Okay seems like something to try :D

Skicka en kommentar