4

Recently, I struggled trying to figure out if some methods, functions in my architecture was at the good place; in the correct layer. I want to follow the repository pattern of Martin Fowler to decouple my service layer from the database.

The definition explained by Martin Fowler on his web site, say:

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.

The problem is that I have a lot of requirements where I must get for example the sum of all invoices. As you can understand, the sum of all invoices is a scalar value. If I follow the definition of Martin Fowler, what I should do is create a function that returns a list of domain objects from my repository layer that is receive by the service layer which loop throw the objects to calculate the total. It is also possible that I don't understand the essence of what this pattern means...

I know that performance should not be a concern while designing the application because maintainability is better but in the case, it's in my view a complete waste of time in development and performance to not create a function in the repository layer that returns a decimal value that correspond to the total of invoices and returns this same value from the service layer. Materializing a list of objects and then just using a single property is an overkill even if you can add some lazy loading strategy with an ORM.

Is it correct to return scalar value from the repository layer or should I resist to the temptation and always returns domain object(s) from this layer and process all the business logic in the service layer?

I also have a lot of places where my presenters calls directly my repository instead of calling the service layer which then call the repository layer. It is correct; acceptable to call this repository pattern outside of the service layer?

Note that I don't want to return a IQueryable result from my repository layer because this will be in total contradiction with the Law of Demeter.

Also, I don't want to set the query directly in my service layer because I want to be able to completely unit testing this layer; not doing integration test.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Samuel
  • 12,073
  • 5
  • 49
  • 71
  • I see no problem to returning a scalar value. As for calling the repository from the UI is correct in some situations (filling combobox for instance). It's ok if it's not processed before shown. That's just my opinion though – Mathieu Apr 24 '12 at 02:20

2 Answers2

2

The problem is easily solved with CQRS (as a concept). Have a specialized query only repository which can be used by the UI (or by the controller when using MVC). That repo can query directly the db (ORM entities it doesn't really matter) and return what you need.

Keep the 'heavy' domain objects and the corresponding repository only for when updating the model.

MikeSW
  • 16,140
  • 3
  • 39
  • 53
1

I had similar issues and I ended up having a base and derived repository interfaces. The base would have standard methods: Fetch, Update, etc. while the derived interface would have specific methods (get the scalar value, in your case).

public interface IRepository { ... }

and

public interface IInvoiceRepository : IRepository 
{ 
  int GetTotal(); 
}

You then create an InvoiceRepository class which implements the interface. Is better to implement the business logic in a separate class, say InvoiceBusinessObject which gets a dependency injection of type IInvoiceRepository (use a parameter in the constructor). Never use the implementation in your business layer.

public class InvoiceBusinessObject
{
  private IInvoiceRepository rep;

  public InvoiceBusinessObject(IInvoiceRepository rep)
  {
    this.rep = rep;
  }

  public int GetTotal()
  {
    return rep.GetTotal();
  }
}

The service layer can instantiate the InvoiceRepository class and inject the instance into the business object class:

public int GetTotalFromService()
{
  IInvoiceRepository rep = new InvoiceRepository();
  InvoiceBusinessObject bizObj = new InvoiceBusinessObject(rep);
  return bizObj.GetTotal();
}
dan radu
  • 2,772
  • 4
  • 18
  • 23
  • This way seems very convoluted IMO and I don't think it's appropriate for a business object to only hide a repository. – MikeSW Apr 24 '12 at 15:19