A következő címkéjű bejegyzések mutatása: JPA. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: JPA. Összes bejegyzés megjelenítése

2017. október 24., kedd

Tipp and tricks using Spring Data



Spring Data is a very comfortable way of defining DAO objects for your project. It can generate a DAO for your entity class, and provide all basic CRUD functions out of the box. You only need to define an interface, inherited from CrudRepository.

For more information of Spring Data basics I recommend reading following resources
  • http://projects.spring.io/spring-data
  • https://www.petrikainulainen.net/spring-data-jpa-tutorial/
It is however not always enough to use the basic functionality of Spring Data. I collect here some more interesting examples of using the possibilities of the framework.

Searching for String with prefix using Query


@Transactional
@Repository
public interface PushServiceConfigurationDao extends CrudRepository<PushSecrviceConfiguration, String> {

@Query(value = "SELECT c.value FROM PushSecrviceConfiguration c where c.key = UPPER(CONCAT('GOOGLE_GCM_API_KEY_', :appName))")
public String findGmcAuthKeyByAppName(@Param("appName") String appName);
}

Get record count


@Query(value = "SELECT COUNT(l) FROM Logic l where l.enabled = true AND l.gateway.id = :gatewayId")
int numberOfEnabledLogicsByGatewayId(@Param("gatewayId") String gatewayId);

Using enum as search parameter


@Query(value = "SELECT t FROM Logic t where t.gateway.id = :gatewayId and t.logicType = :logicType")
List<Logic> findAllByGatewayIdAndLogicType(@Param("gatewayId") String gatewayId, @Param("logicType") LogicType logicType);

Using @EntityGraph to control eager loading of elements


Defining the entitygraph in your domain class


@NamedEntityGraphs({
 @NamedEntityGraph(name = "graph.gateway.authTokens", attributeNodes = @NamedAttributeNode("authTokens")),
 @NamedEntityGraph(name = "graph.gateway.devices", attributeNodes = @NamedAttributeNode("devices"))
})
public class Gateway implements java.io.Serializable { ...

Using @EntityGraph annotation in your query

@EntityGraph(value = "graph.gateway.authTokens", type = EntityGraphType.LOAD)
Gateway findByDeviceCode(String deviceCode);

Defining native update command


@Modifying
@Query(value = "UPDATE ws_message_queue SET processor_id = ?2 WHERE backend_ip = ?1 AND processor_id is null", nativeQuery = true)
int reserveMessagesForProcessing(String backendIp, String processorId);


2016. március 29., kedd


Lazy init vs initialization by definition for collection typed properties of JPA entities


How to initialize a collection typed property of a JPA entity? In order to make the Unit testing easier and the client code cleaner it is advisable to get an empty collection from the entity. Even if the entity has not been initialized by the JPA (based on database state), or in case of a newly instantiated entity. If null can be returned by the getter, the client code needs to be handle the situation.

In Unit tests, especially by using mocked objects, it can be extremely ugly to let the client code to check for possible null values.

We have two possibilities:

  1. Initialize by declaration
    JPA itself doesn't care whether the collection is initialized or not. When retrieving an Order from the database with JPA, JPA will always return an Order with a non-null list of OrderLines.

    It does so, because a relation can have 0, 1 or N elements, and that is best modeled with an empty, one-sized or N-sized collection. So it's best to make that an invariant by always having a non-null collection, even for newly created instances of the entity. That makes the production code creating new orders safer and cleaner. That also makes your unit tests, using Order instances not coming from the database, safer and cleaner.
    It is also possible to use Guava's immutable collections, e.g.,
    import com.google.common.collect.ImmutableList;
    // ...
    @OneToMany(mappedBy="order")
    List<Order> orders = ImmutableList.of();
    In this way, we are never creating a new empty list, but reusing the empty list of the framework. Therefore the performance argument is no longer relevant.

    In case of the setter can be accessed by the client, it might be a chance, to set the collection to null. In this case, a NullPointerException might occur. Therefore it is a good practice to avoid setting a collection to null in the setter.
  2. Lazy initialization in getter method
    There can be problems with lazy init using with hibernate, related to the search for entities. The JPA specification defines Flushmode to determine if the entities need to be written to the database (see https://en.wikibooks.org/wiki/Java_Persistence/Querying#Flush_Mode for details). In case of lazy init, Hibernate thinks the entity dirty, in case it has been loaded with null collection, but the getter returns an empty collection. If Flush Mode is set to AUTO, Hibernate writes the entity into the database before the search, which might cause performance problems.