5

I'm writing a console application that does a good amount of data retrieval from stored procedure recordsets. For each recordset type I'm working with, I have a Repository that uses EF with custom complex types to retrieve the data:

public interface IBalanceSheetRepository
{
    IEnumerable<BalanceSheetRecordDTO> GetBalanceSheetRecords();
}

public class BalanceSheetRepository : IBalanceSheetRepository
{
    DBContext _context;

    ...

    public IEnumerable<BalanceSheetRecordDTO> GetBalanceSheetRecords()
    {
        ObjectResult<BalanceSheetRecord> results = _context.GetBalanceSheet();
        return results.Select(CreateBalanceSheetDTOFromDAO);
    }

    private static BalanceSheetRecordDTO CreateBalanceSheetDTOFromDAO(BalanceSheetRecord dao)
    {
        return new BalanceSheetRecordDTO { ... };
    }
}

Here, BalanceSheetRecord is a complex data type that I created in the designer. I created a DTO to avoid coupling since the BLL should not know about the BalanceSheetRecord type.

Here's my question: Since the DTO type is used in the method signature of the repository interface, and since my BLL will ultimately use the repository & be returned a collection of the DTOs, it seems to be a cross-cutting concern. Therefore I have the DTO living in a separate "Infrastructure" assembly, along with the repo interfaces. Is this good practice for what I'm trying to achieve, or did I take a wrong turn somewhere?

Also: Is it bad practice to new up the data context in my repository? Is some amount of coupling OK when both components belong to the DAL? I want to use DI but it seems more useful for swapping out the DBContext implementation of the repo for a TestBalanceSheetRepository, for instance.

Chris Trombley
  • 2,112
  • 1
  • 16
  • 24

1 Answers1

7

I prefer to return actual entities from my repositories. This way when you need to orchestrate complex interactions between different entities in the service layer, there's no converting back and forth to DTO's. The service layer then projects entities into DTO's when returning data to the application layer.

I know there are purists who say that all interaction between layers should be done with DTO's, but I find that impractical. The service layer will end up coupled to the entities anyway, so it's not like you're adding coupling.

It also limits the projection/flattening of DTO's to entities to the service layer. Which to me is a plus since these activities add to complexity and decreases performance.

Your data context is your unit of work. The "one unit of work per repository" idea is an anti-pattern. Units of work should be scoped by the service layer, which may involve 1-many entities from 1-many repositories. If each repository has a different unit of work, you lose your ability to have service layer calls maintain consistent transactions easily.

Brook
  • 5,759
  • 3
  • 29
  • 45
  • Agreed. Repositories should return domain objects. At boundary between systems, like a web service, it can be better to return DTOs, so that an external system isn't tightly coupled to your domain model. – Carl Raymond Jun 10 '11 at 18:31
  • 1
    @Carl Raymond: Right, but I would never expose a repository directly via a web service. I would always put a service layer on top of it which did the projecting/flattening of DTO's and orchestrating. Exposing a repository directly would give you very "CRUDy" service calls and an overly chatty application, with business logic scattered about in the clients. – Brook Jun 10 '11 at 18:36
  • That's what I mean. I suppose when I say "can be better" I mean "almost always is better, unless you have some really special case". I wasn't thinking about chattiness, but that's another good point. A web service API will be structured differently than a repository to minimize the amount of network traffic to accomplish a task. – Carl Raymond Jun 10 '11 at 18:46
  • As a way of saving time writing your DTOs, you can use [EntitiesToDTOs](http://entitiestodtos.codeplex.com) which generates the DTOs and Assemblers from your EDMX automatically. – kzfabi Nov 23 '12 at 17:28
  • 1
    That's actually something I would advise against. DTO's should be as usage specific as possible, and contain only what they need for a given usage. If you're using a generator to just generate your DTO's with all the fields from the entities, and then reusing the same DTO's across many service calls, you're doing it wrong, IMO. – Brook Nov 26 '12 at 03:03
  • What about if query from repository return anonymous type? Usually when you do Join or GroupBy operation, it returns anonymous type – Willy Jun 18 '14 at 07:26
  • @Willy well you can't return an anonymous type... so in the instances where I have some aggregate that I need to return from a repository I usually just have it return the DTO directly from the repo. What you call it at that point is really just semantics. Is it a Model? well not in the sense that it's bound to a table. Is it a DTO? well it is transferring data... as vague as that is. – Brook Jun 20 '14 at 02:05
  • I've read article from http://stackoverflow.com/questions/5068984/should-the-repository-layer-return-data-transfer-objects-dto that you should not return DTO from repository. Repository is responsible for turning persisted data back to entities (models) and vice versa. It makes me so confused. – Willy Jun 20 '14 at 09:19
  • That's great in a perfect world where the performance cost of the ORM is zero, but in the real world sometimes you need to do aggregates etc in the DB for performance reasons, or sometimes it just isn't really a model, it's a report row or something. Sure you could define a model of the report row and go that route, so we're really just talking about semantics. Either way you've got to get the data from your Persistence layer to your Application layer in a performant way. – Brook Jun 20 '14 at 18:11