Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repository pattern benefits and Spring implementation

Tags:

In the article Don’t use DAO, use Repository there is a pretty good explanation of the differences between DAO and repository patterns.

My brief retelling - DAO makes us to bloat interface with multiple methods, which obstruct changes and testing. In turn, repository encapsulate all customizations/changes with query method, which accept Specification as an argument. When you need a new behavior at repository - you shouldn't change it, instead create a new heir of Specification.

My conslusion - repository pattern is better than DAO due its interfaces are closed to modification.

Am I right so far? Haven't I missed some benefits of repository pattern?

BUT, if you'd look at Spring's accessing data JPA guide, you'll find the next code:

public interface CustomerRepository extends CrudRepository<Customer, Long> {
    List<Customer> findByLastName(String lastName); //each time you need custom behavior you need to add a method
    //...
}

Doesn't it conflict with the previous article? Why Spring's repository force us to add new methods to interface?

like image 406
VB_ Avatar asked Oct 16 '16 09:10

VB_


People also ask

What is the purpose of repository pattern in spring data?

The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.

What is the benefit of repository pattern?

The Repository pattern makes it easier to test your application logic. The Repository pattern allows you to easily test your application with unit tests. Remember that unit tests only test your code, not infrastructure, so the repository abstractions make it easier to achieve that goal.

What is the use of @repository in spring boot?

@Repository Annotation is a specialization of @Component annotation which is used to indicate that the class provides the mechanism for storage, retrieval, update, delete and search operation on objects.

How are spring data repositories implemented?

In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object). Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).


1 Answers

My conslusion - repository pattern is better than DAO due its interfaces are closed to modification

It depends on...
Because repository pattern is more complex since it requires more code to write and has a bigger level of abstraction than DAO pattern for both clients of repository and implementation of it.
When you need to have flexibility in your queries and/or your queries mix multiple entities in the result , repository pattern can address these needs. If you need to have mainly simple crud operations on a table (basic create, read, update and delete operations), I think that using a real repository (so with specifications) may be an overhead.

BUT, if you'd look at Spring's accessing data JPA guide, you'll find the next code:

 public interface CustomerRepository extends CrudRepository<Customer,Long> {
    List<Customer> findByLastName(String lastName); //each time you need custom behavior you need to add a method
     //... }

Doesn't it conflict with the previous article? Why Spring's repository force us to add new methods to interface?

Yes. I think that the problem comes from Spring which uses a fashion term (repository) to stand for a class which is not a repository according to pattern literature. (http://martinfowler.com/eaaCatalog/repository.html)
I think you should consider Spring Repository as DAO since the base functional interface of Spring repository is CrudRepository. And by nature CRUD operations are operations we find in a DAO...

After, nothing prevents you from enriching the repository to provide repository methods with Spring specifications as in the 2.4 point of the official documentation of Spring data.
Spring proposes you to extend the org.springframework.data.repository.CrudRepository interface as in your example. It is the easier way of doing and I imagine it is the most common way of doing...

public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor {
 …
}

And JpaSpecificationExecutor provides methods which use specifications and therefore promote the reduction of duplicate processings in queries source code :

/*
 * Copyright 2008-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.jpa.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

/**
 * Interface to allow execution of {@link Specification}s based on the JPA criteria API.
 * 
 * @author Oliver Gierke
 */
public interface JpaSpecificationExecutor<T> {

    /**
     * Returns a single entity matching the given {@link Specification}.
     * 
     * @param spec
     * @return
     */
    T findOne(Specification<T> spec);

    /**
     * Returns all entities matching the given {@link Specification}.
     * 
     * @param spec
     * @return
     */
    List<T> findAll(Specification<T> spec);

    /**
     * Returns a {@link Page} of entities matching the given {@link Specification}.
     * 
     * @param spec
     * @param pageable
     * @return
     */
    Page<T> findAll(Specification<T> spec, Pageable pageable);

    /**
     * Returns all entities matching the given {@link Specification} and {@link Sort}.
     * 
     * @param spec
     * @param sort
     * @return
     */
    List<T> findAll(Specification<T> spec, Sort sort);

    /**
     * Returns the number of instances that the given {@link Specification} will return.
     * 
     * @param spec the {@link Specification} to count instances for
     * @return the number of instances
     */
    long count(Specification<T> spec);
}

But I think that it will create the Frankenstein creature : half DAO, half repository.

The other solution is implementing directly the base and marker interface : org.springframework.data.repository.Repository and the JpaSpecificationExecutor interface like that :

public interface CustomerRepository extends Repository<Customer, Long>, JpaSpecificationExecutor {
 …
}

In this way, you could have a real repository, with only specification methods.
I don't know if it works. I never tried that.

Edit : response to comment

Repository pattern is a concept that Hibernate doesn't provide with an out of box solution.
But Hibernate and more generally the JPA 2 specification provide indeed Criteria as basic ingredient to create specifications as classes.
You can then create a custom class which implements the Repository pattern by proposing required methods with specifications as input. I think you can use ORM and repositories since you can use ORM with specifications by using criteria API. Some people oppose ORM and Repository and I disagree. ORM is not based on DAO pattern. DAO is the way to manipulate data in database. ORM is the way to structure data objects to represent database structures. For example, by using both, you can benefit both from the flexibility of specifications and the power of relational-object mapping and of the weaving between entities.
If you don't use ORM or ORM like as IBatis, you should code yourself what ORM offers to you : the object relational mapping.

like image 93
davidxxx Avatar answered Sep 22 '22 16:09

davidxxx