Please explain the Repository-, Mapping-, and Business-Layer relations and responsibilities
<p>I've been reading <em>a lot</em> about this stuff and I am currently in the middle of the development of a larger web-application and its corresponding back-end. </p>

<p>However, I've started with a design where I ask a Repository to fetch data from the database and map it into a DTO. Why DTO? Simply because until now basically everything was simple stuff and no more complexity was necessary. If it got a bit more complex then I started to map e.g. 1-to-n relations directly in the service layer. Something like:</p>

<pre class="lang-java prettyprint-override"><code>// This is Service-Layer
public List&lt;CarDTO&gt; getCarsFromOwner(Long carOwnerId) {

    // Entering Repository-Layer
    List&lt;CarDTO&gt; cars = this.carRepository = this.carRepository.getCars(carOwnerId);
    Map&lt;Long, List&lt;WheelDTO&gt;&gt; wheelMap = this.wheelRepository.getWheels(carId);

    for(CarDTO car : cars) {
        List&lt;WheelDTO&gt; wheels = wheelMap.get(car.getId());
        car.setWheels(wheels);
    }

    return cars;
}
</code></pre>

<p>This works of course but it turns out that sometimes things are getting more complex than this and I'm starting to realize that the code might look quite ugly if I don't do anything about this.</p>

<p>Of course, I could load <code>wheelMap</code> in the <code>CarRepository</code>, do the wheel-mapping there and only return complete objects, but since SQL queries can sometimes look quite complex I don't want to fetch all <code>cars</code> <em>and</em> their <code>wheels</code> plus taking care of the mapping in <code>getCars(Long ownerId)</code>.</p>

<p>I'm clearly missing a Business-Layer, right? But I'm simply not able to get my head around its best practice.</p>

<p>Let's assume I have <code>Car</code> and a <code>Owner</code> business-objects. Would my code look something like this:</p>

<pre class="lang-java prettyprint-override"><code>// This is Service-Layer
public List&lt;CarDTO&gt; getCarsFromOwner(Long carOwnerId) {

    // The new Business-Layer
    CarOwner carOwner = new CarOwner(carOwnerId);
    List&lt;Car&gt; cars = carOwner.getAllCars();

    return cars;
}
</code></pre>

<p>which looks as simple as it can be, but what would happen on the inside? The question is aiming especially at <code>CarOwner#getAllCars()</code>.</p>

<p>I imagine that this function would use Mappers and Repositories in order to load the data and that especially the relational mapping part is taken care of:</p>

<pre class="lang-java prettyprint-override"><code>List&lt;CarDTO&gt; cars = this.carRepository = this.carRepository.getCars(carOwnerId);
Map&lt;Long, List&lt;WheelDTO&gt;&gt; wheelMap = this.wheelRepository.getWheels(carId);

for(CarDTO car : cars) {
    List&lt;WheelDTO&gt; wheels = wheelMap.get(car.getId());
    car.setWheels(wheels);
}
</code></pre>

<p>But how? Is the <code>CarMapper</code> providing functions <code>getAllCarsWithWheels()</code> and <code>getAllCarsWithoutWheels()</code>? This would also move the <code>CarRepository</code> and the <code>WheelRepository</code> into <code>CarMapper</code> but is this the right place for a repository?</p>

<p>I'd be happy if somebody could show me a good practical example for the code above. </p>

<hr>

<h3>Additional Information</h3>

<p>I'm not using an ORM - instead I'm going with jOOQ. It's essentially just a type-safe way to write SQL (and it makes quite fun using it btw).</p>

<p>Here is an example how that looks like:</p>

<pre class="lang-java prettyprint-override"><code>public List&lt;CompanyDTO&gt; getCompanies(Long adminId) {

    LOGGER.debug("Loading companies for user ..");

    Table&lt;?&gt; companyEmployee = this.ctx.select(COMPANY_EMPLOYEE.COMPANY_ID)
        .from(COMPANY_EMPLOYEE)
        .where(COMPANY_EMPLOYEE.ADMIN_ID.eq(adminId))
        .asTable("companyEmployee");

    List&lt;CompanyDTO&gt; fetchInto = this.ctx.select(COMPANY.ID, COMPANY.NAME)
        .from(COMPANY)
        .join(companyEmployee)
            .on(companyEmployee.field(COMPANY_EMPLOYEE.COMPANY_ID).eq(COMPANY.ID))
            .fetchInto(CompanyDTO.class);

    return fetchInto;
}
</code></pre>