13

I am trying to get an answer to the two quite similar questions here:

Should I convert an entity to a DTO inside a Repository object and return it to the Service Layer?

or

Is it okay to return DTO objects from the Repository Layer?

Right now I am stuck in my Servlet (Servie Layer) that e.g. tries to retrieve all Restaurant objects from a RestaurantOwnerRepository:

// RestaurantOwnerService (Servlet)

@Override
@Transactional
public List<RestaurantDTO> getAvailableRestaurants() {

    List<Restaurant> availableRestaurants = restaurantOwnerRepository.getRestaurants(getSessionId());

    return null;
}

where Restaurant is a @Entity annotated class - which appears to be the first thing I shouldn't do because the Service Layer does now know about a very low-level object which imho violates the attempt to abstract my data in each layer.

That wouldn't be the case if I e.g. converted each Restaurant to a RestaurantDTO - but should I do that?

Basically change:

// RestaurantOwnerRepository

@Override
public List<Restaurant> getRestaurants(String sessionId) {

    RestaurantOwner restaurantOwner = this.get(sessionId);

    // .. getting restaurants ..

    return availableRestaurants;
}

to

// RestaurantOwnerRepository

@Override
public List<Restaurant> getRestaurants(String sessionId) {

    RestaurantOwner restaurantOwner = this.get(sessionId);

    // .. getting restaurants ..

    return ConvertEntity.convertRestaurants(availableRestaurants);
}

and have a util ConvertEntity for every entity like this for example:

public class ConvertEntity {

    public static List<RestaurantDTO> convertRestaurants(List<Restaurant> restaurants) {
        // ...
    }

}

but this just does not feel like the best solution to me.. what could I do here?


One important thing to mention would be that this comes form a GWT project. That means that I am using e.g. RestaurantDTO on the server and on the client side as it is contained inside a shared project.

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
  • Your second question must be *"Is it okay to return **entities** from the Repository Layer?"*, right? Also, could you check your return types? I a bit confused, e.g. in your third snippet. – sp00m Jul 31 '15 at 09:45
  • Make the DTO an interface and let `Restaurant` implement it. The entity and the DTO will share most of the implementation anyway. – Marko Topolnik Jul 31 '15 at 09:45
  • Just return it to the service layer. – Stefan Jul 31 '15 at 09:45
  • @sp00m I state in my question that I am aware of the fact that I shouldn't return an entity from a repository. Right now *I do so* but I am also not sure if it is okay to return just a DTO from a repository or if there should be another abstraction layer in between. – Stefan Falk Jul 31 '15 at 09:46
  • @MarkoTopolnik The problem with that is that `RestaurantDTO` is actually a class shared by the server *and* the client - I am using GWT (added this detail to my question now). – Stefan Falk Jul 31 '15 at 09:51
  • I thought you could just share the `RestaurantDTO` interface, but maybe I don't know GWT well enough. – Marko Topolnik Jul 31 '15 at 10:05
  • @MarkoTopolnik Well yes, you're right of course.. So you mean I could let do it like this `@Entity public class Restaurant implements IRestaurantDTO { /*..*/ }` and just return `IRestaurantDTO` in from my repository and pass that through the service layer to my client? – Stefan Falk Jul 31 '15 at 10:09
  • Exactly, that way you don't need to copy data between two almost identical implementation classes. – Marko Topolnik Jul 31 '15 at 10:10

1 Answers1

12

It's more clear now after your comment. Let's try again:

First, some clarifications: Your RestaurantOwnerRepository implements the repository pattern. Your @Entity annotated objects are hibernate entities and also DAO proxies. Your RestaurantOwnerService is a GWT-Service which can only return a DTO shared with the client and server.

So in a very simple server-side setup, you have a DB-Backend, access to the data via hibernate as a persistence layer, and a service layer as rest-service. In such a setup your hibernate entities are shared among the whole server side code. Your service layer is converting the entities to json format, for example. Deal?

Your "advanced" setup

  • Persistence layer
    • with Hibernate (delivering @Entity-Annotated objects)
    • maybe other stuff, too
  • Repository Layer (unclear for you what to return)
  • Service Layer (GWT Servlets, delivering DTOs which are shared with the client side)

Definition of Repository-Layer: In my opinion, it's an abstraction for different data/persistence layers. It doesn't provide business logic, which is more the purpose of a further business layer. The business layer compiles the outputs of the upper layer together, makes computations and returns the results. But looking according to your comment, this may also be the case in your repository layer. But it's ok for our clarification.

Your question: Is it okay to return DTO objects from the Repository Layer?

Answer: No, it is not really okay to return a DTO from the "repository" layer.

Why: 1. Your DTO is a domain entity transferred into a format which can be sent to the client side. It has limitations so that some server side libraries cannot be used in them. 2. Consider the case that you also want to provide other service layers. A REST-Interface maybe, another GUI-Framework maybe. They all have their own limitations for transferring the domain entities. Do you really want to duplicate the repository layer for each service layer? 3. Consider the case where you want to extend your repository/business layer so that it will use the output of your RestaurantOwnerRepository. Do you really want to work on DTOs there?

These are why the creation of a DTO is the purpose of a service layer. So the DTO is shared among the client side, and your service layer. In the same sense, you need objects, shared among the service layer and your repository layer. I call these domain entities. These are returned from the repository layer and used by the service layer. Again the same between the repository layer and persistence layer. The persistence layer for example returns the Hibernate entities which are used on the repository layer.

In most cases, it is ok to propagate your objects from multiple layers downwards. So you can return your hibernate entites from the repository layer to the service layer. Newer versions of GWT even allow to use JPA-entities on the client side with a special setup. So your service layer can further return your persistence entities.

fatih
  • 1,395
  • 10
  • 9
  • 2
    Well, no `RestaurantOwnerRepository` is really a repository (pattern). Each `@Entity` annotated class is actually a DAO as Hibernate wraps a proxy around it. I don't understand why would I share `@Entity` classes in my whole project? Only the server should know about those and imho their usage ends with the Repository Layer. I also don't understand what you mean by "compilation of repository objects". Shouldn't the Repository Layer return business objects which are already compilations of entity objects? – Stefan Falk Aug 03 '15 at 16:16
  • according to your comment, I edited my response. I hope it's more clear now. – fatih Aug 04 '15 at 11:05
  • I didn't see your edit because you didn't notify me with @stefanfalk but thanks for your extended answer! I think I understand and it does make sense why the repository layer should not return DTOs now! – Stefan Falk Aug 19 '15 at 14:29