What type to return when querying multiple entities in Repository layer?

被刻印的时光 ゝ 提交于 2019-12-04 19:32:42


I have the following layers involved in this question:

  • Service Layer (Using IoC to call Repository)
  • Domain Model (POCO / Domain Entities, defined repository Interfaces)
  • Repository Layer (EF .edmx and implemented repositories)

A lot of times it's really straight forward: Repository layer queries database via Entity Framework and returns IList<SomeDomainEntity> to caller which was Service Layer. The type returned is a type defined in the Domain Model.

The problem I'm running into is when I need to query across POCOs A,B, and C and get data from all to be returned. Since I don't handle any logic in the repository I need to return this data back to the Service layer to be processed (either directly or more likely by calling some logic on domain model). However I don't have a single type anymore from the results of the repository query to return to the caller.

An anonymous type of course handles this in examples I see, but since I'm not processing that logic from returned data directly in the Repository and it needs to be returned, I need a physical type to return. Here are some solutions I thought of but not sure I like any:

  1. Create a new domain entity in Domain Model that essentially is a composition of all the data I queried, so this new single type may be returned. This seems wrong to create abritrary types to satisy query needs.
  2. Make the service layer call the individual repositories on A,B,C entities separately and then deal with the data from each returned object. This seems like a lot of extra work.
  3. Create a ViewModel to return. This seems out of place to me as well. I leverage ViewModel classes heavily between my service layer and UI layers, but never seen them leveraged for return from the repository.

I can't be the only one querying across multiple entities to get a conglomeration of data back that needs to be added to a type and returned to the caller. What is a common practice or standard way of going about this to solve my problem?



If those entities are related and you query all of them in one place then you should try to find an aggregate root of them in your domain model or if it doesn't exist yet you should introduce a new one, as you said in the first option. This is not wrong until it makes sense. It should model a domain concept and you probably have one because you created that repository method.

If those entities are not related (well, probably related in some way, but not that tightly as above) and you just want to get them in one go then you should handle that in the service layer where you can use multiple repositories and compose a result object.

You probably heard of the concept of navigation properties and eager loading but I write it here because it may be another answer to your question (I don't see your domain model)

I wouldn't go with your third suggestion (create viewmodels in the repository) because it breaks the separations.


Different entities can relate to each other whithout one of them being an aggregate root. Services are used to these kind of queries. I usually do something like this:

public class MyService
    IEnumerable<UserWithMessages> Find()
        var messages = _messageRepository.FindAll();
        var userIds = _messages.Select(x => x.UserId).Distinct().ToArry();
        var users = _userRepository.Find(userIds);
        return users.Select(x => new UserWithMessages(x, messages.Where(x => x.UserId == x.Id));

It's just two DB queries which can utilize indexes in the DB. So It should be pretty fast.


I suggest you to use DTO (Data Transfer Objects) for this purpose. It's a common practice to separate your service layer from the view, and DTOs allow you to share only the important information necessary for the views.

There are various ways to implement this part of the system depending of the size of the system. In small systems you can use extension methods to map your POCO entities in data transfer objects

I suggest you take a look to "AutoMapper". I think this will be really usefull for you