views:

166

answers:

3

Does role / view logic belong inside or outside of the Repository Pattern?

For example, I have a table of products, and each product has 5 price fields - one for each type of customer (wholesale, retail etc).

I only want to show the appropriate price to the appropriate user.

If I have a repository of these products, should the Product business object returned, contain all 5 prices, and somehow only display the relevant price?

If so, what is a good pattern to use?

Should I perhaps create a view object, which takes a business object and a role and determines the right price to show? Or shall I put that logic inside the business object?

(FYI: I will be building the solution in ASP MVC if you think it will help frame the response)

+3  A: 

Yes, your repository should return all five prices, and your objects should contain the business logic that decides which customer receives which price. The objects should be capable of making this decision regardless of where their data came from.

This approach will also allow you to test your pricing logic independently of your data access concerns - for example, by using a 'dummy' repository, by manually creating a product with the five price fields already populated, or by using a mocking framework to mock your repository calls. Moving this sort of logic outside your business objects - e.g. putting it in your data access layer - can lead to an anti-pattern known as the Anemic Domain Model.

EDIT: In response to your comments:

The term "repository" specifically refers to a data access pattern that returns fully-populated collections (aggregates) of business objects. If you find that returning DTOs is a better solution for your problem, then go ahead and do so, but you may confuse people if you use the term "repository" to refer to other data access patterns. Personally, I'd stick with the repository approach and return fully-populated business objects, because I prefer working that way, but as with so much, it depends on the scale and complexity of the system you're building.

To expose your pricing logic, you probably just want to use a method like:

public class Product {
    public decimal GetPriceFor(User user) {
        // logic to determine per-user pricing goes here:
    } 
}
Dylan Beattie
This idea feels 'right' to me. Should the repository return my BO or just a DTO, which I then use to create the BO? How would I access the price on this BO? Presumably with a method that takes a role as parameter?
Schneider
I've edited my answer to address these issues - comments don't provide enough space to really explain the answers! Hope that's OK...
Dylan Beattie
Thanks. Last question: If I have a method that needs a User parameter, how can I do simple binding to this value from the View? Would I pass the user + product as part of the 'model' for the view to bind to? Or should the view bind to a simple presenation type object?
Schneider
+2  A: 

One approach is to create a service layer that contains your business logic. The service layer interacts with the repository applying any rules or filters that you require. This means anything returned from the service layer is just a plain c# object (POCO).

Almond
Wouldn't this service layer lead to the 'anemic domain model' that Dylan talks about?
Schneider
A: 

After designing some products with an extra data access layer, I would say: Design it with the functional dependencies in mind!

Suppose you have the following very common structure for the data dictionary: productName, productDetail, productPrice, customerName, customerDetail.

One can easily identify the relations: Customer and Product.

class Customer: customerName, customerDetail

class Product: productName, productDetail

But there is a third relation to draw, it is

class CustomerProduct: customerName, productName, productPrize

Because you can reason that only customerName X productName |-> productPrize. For the use case Customer C wants to know the price of product P:

Customer('C').prize('P')

The method prize must be delegated to know the exact prize and you have a clean separation of concerns. To be clear about the point: the BO will show no prize to the customer. Just the method has access to the delicate data. And this access you can restrict.

Roman Glass
Thanks for the response. I found you answer a little bit complicated to follow but I think I understand the essence - you are saying to provide a method to access the price. Presumably that method must take a parameter such as the users role?
Schneider