1
public interface IRepository<TEntity> 
{
    TEntity FindById(Guid id);
    void Add(TEntity entity);
    void Remove(TEntity entity);
}

This is a simple generic repository. If I have a Product entity, this repository can insert, update, and delete (using Entity Framework).

But I have report based types that I created.

For example:

  • Products that grouped by salesmen.
  • Number of orders sent by each shipper.

    public class OrdersWithShipper {
         public string ShipperName{get;set;}
         public string NumberOfOrder{get;set;}
    }
    

And so on.

So I should create complex queries to many tables that related. But query result object is not representing with repository TEntity entity type.

I have many report type like this. How can I solve this problem?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
barteloma
  • 6,403
  • 14
  • 79
  • 173
  • 2
    You want to convert entities into viewmodels in the controller, not from a repository. Automapper may help. – danludwig Mar 02 '15 at 15:21
  • 1
    I swear down, this is like the 10th Repo Pattern problem to do with EF and C# in the last 7 days. There needs to be a hit at the top of google with a god like answer for all these questions. They're all the same. – Callum Linington Mar 02 '15 at 15:30
  • 2
    And at bookmarker, you should consider not using the Repo pattern. It looks like it will inhibit what you are doing. Rather than help you out. – Callum Linington Mar 02 '15 at 15:31
  • @danludwig +1 for mentioning AutoMapper – Ian CT Mar 02 '15 at 15:37
  • @CallumLinington you said this is 10th Repo Pattern problem, is there link about a true solution? – barteloma Mar 03 '15 at 06:53
  • There are no "true" solutions. With coding there are many answers to a single problem, and it just comes down to preference and maintainability. I can write a blog post about how I do it if that would help? – Callum Linington Mar 03 '15 at 08:34

2 Answers2

2

The direct problem of this question is:

So I should create complex queries to many tables that related. But query result object is not representing with repository TEntity entity type.

I would say you should not be using the repository pattern here as it breaks it. E.g a repository should be dealing with returning and managing the domain object it is designed for, in order to support domain behavior, not random query objects to support reporting behavior.

By not sticking to the same type you will almost certainly end up not knowing where to draw the line, e.g what query object goes with what repository etc... So you should just keep it simple.

Apply a different pattern to reporting (or querying) for example. Maybe create classes for your view models (View Model Builders?) that are directly dependent on IDbSet<T> for their querying logic.

Or, abstract further and have a query handler / query provider pattern (this would be my choice).

Look at the answer here:

Well designed query commands and/or specifications

I have used similar pattern to this with great success.

Community
  • 1
  • 1
James Simpson
  • 1,150
  • 6
  • 11
  • I agree, repository is not a good pattern for mapping from entity / domain data models to MVC / presentation view models. – danludwig Mar 02 '15 at 16:06
0

My technique in doing this is to wrap the Repository in a Service class that can accept the ViewModels. In other words, my Controllers are using the Service classes that I make and not the repositories directly. Also, I use the AutoMapper library to map

Example below:

public class OrderWithShipperProductService()
{
    public ProductRepository { get; set; }

    public OrderWithShipperProductService(ProductRepository repo)
    {
        this.ProductRepository = repo;
    }

    public void AddOrderWithShipperProduct(OrderWithShipperProduct model)
    {
        var entity = Mapper.Map<TEntity>(model);
        ProductRepository.Add(entity);
    }
}

You may need to learn Automapper here. But you may also map it yourself in the constructor if you want. Or you may also create your own mapping functions.

Ian CT
  • 1,301
  • 2
  • 12
  • 22
  • 2
    I'm not saying your wrong by any means, but this creates far more work than not using the repo pattern. The repo is now becoming an unecessary restrictive mediator between the service and EF DbContext. IMO – Callum Linington Mar 02 '15 at 15:33
  • that is a very nice and unique perspective :) but in the company I work in I have never encountered that way of thinking @CallumLinington upvote for you. Also, I have not endorsed the repo pattern here. I also donot use the repo pattern. I use repos but I donot use the generic CRUD repos if thats what you mean. – Ian CT Mar 02 '15 at 15:35
  • 1
    Problem is IDbSet is too similar to IRepository to really warrant an IRepository when you use EF – James Simpson Mar 02 '15 at 15:39
  • For me, generic CRUD repositories is what's too similar to IDbSet. Repos are still useful if they encapsulate custom queries. – Ian CT Mar 02 '15 at 15:41
  • 1
    @chutzzz maybe. Systems based on CQRS can encapsulate query handlers, which contribute to the non-usefulness of non-EF-based repositories. – danludwig Mar 02 '15 at 15:45
  • @JamesSimpson yeah that's it, there is no point adding more to get less. It seems redundant also when EF has the Unit of Work pattern implemented as well. Or at least, if you encapsulate work in a `using (var context = new DbContext)` you are following that pattern anyway. – Callum Linington Mar 02 '15 at 16:05
  • @chutzzz Thanks :), I also find that I'm never manipulating or retrieving one domain object at a time with EF, so having several repos means more lines. – Callum Linington Mar 02 '15 at 16:06
  • This is, seriously, my first time to hear people say that repos are useless :o can you give me an article that supports this opinion? @CallumLinington? this could be a defining learning experience for me – Ian CT Mar 02 '15 at 19:48
  • @IanChuTe to be honest with you, I don't know any articles, all I can say is, I was once someone who used a repo then created a generic and did all this stuff only to find things not working, not being consistent and code being far too complicated. When I striped it back to just use the DbContext life was real good. – Callum Linington Mar 03 '15 at 08:33
  • @lanChuTe according to your solution, I should two kind of repository. One of them will be working with domain entities like ProductRepository and other one will be working report Types like ProductOrderReportGenerator. – barteloma Mar 03 '15 at 08:57
  • @bookmarker Nope. Only one repository class. Just for the domain entities. The service class is not a repository. – Ian CT Mar 03 '15 at 08:58