How to query in a recursive way using QueryDSL+spring data jpa+gradle+mysql? - spring-data-jpa

#Entity
public class Department {
private Long id;
private Long parentId;
}
I want to query all of children departments (include children's children and so on) by a department id in a recursive way with QueryDSL (using 5.0.0).
I know that it can be implemented using the withRecursive method of JPASQLQuery.
I read the Maven configuration in the official tutorial, but gradle doesn't know how to configure it, can you provide an example?
And provide an example of recursive query? thank you!
There is no #OneToMany or #ManyToOne, only parentId.

Related

Spring Data REST - How to update entities in child collections of aggregates

Following the principles of DDD and using Spring Data REST/HATEOAS what is the best way to manipulate entities in child collections.
For example:
#Entity
public class Topic{
#Id #GeneratedValue
private Long id;
private String title;
#OneToMany
private Set<Post> posts;
…
}
#Entity
public class Post{
#Id #GeneratedValue
private Long id;
private String title;
private String body;
#OneToMany
private Set<Comment> comment;
…
}
#Entity
public class Comment{
#Id #GeneratedValue
private Long id;
private String text;
}
Spring Data REST (SDR) inlines domain objects that don't have their own repositories when serializing to JSON.
{
"title" : "Spring",
"posts" : [{
"title": "Spring Boot 1.5.8",
"body": "blah",
"comments":[ {"text":"great!"} , {"text":"boo"},
{"text":"comment that should be removed by moderators"}]
}]
"_links" : {
"self" : {
"href" : "http://localhost:8080/topics/1"
}
}
}
The issue I have is that I am unable to get a handle on individual objects in a collection because SDR not only hides ids for all entities but also does not provide a 'self' link for inlined entities.
I don't want to simply PUT the whole aggregate because inline with DDD I want to handle changes of state via dedicated 'controller' resources, allowing the raising of event to trigger additional business logic. Consider adding/removing/updating a post comment in the example above.
I'm left with an number of options none of which I really like.
Reverse all my unidirectional relationships and create repositories for all the child entities, effectively abandoning the DDD aggregate design concept.
Move to bi-directional relationships, create repositories for all child entities and compose the aggregate using a Projection. The general advice from the internet (including SDR developer Oliver Gierke) is to avoid bi-directional relationships if at all possible due to performance considerations and having to manually manage the relationship.
Add a GUID or some other immutable unique identifier to the child entities. This feels wrong considering the whole point of HATEOAS is that the URI is the identifier. Even this breaks down when dealing with children of children.
I'm currently feeling inclined towards 2 as it seems to be the only workable option that allows me to retain the design principle.
Has anyone encountered and overcome a similar problem?
Edit:
I've come up with a possible solution:
Move to bi-directional relationships without creating repositories for child entities. This will give me the parents key so that I can compose a 'self' & other links using a ResourceProcessor e.g /topics/1/posts/add-post which I can handle via a RestController. This should work well enough at 1 level deep, it may have performance implications for deeper nesting e.g. /topics/1/posts/1/comments/add-comment as with JPA there's going to be a cost associated with doing the lookups to traverse the parent relationships. This would be done in tandem with #Alan Hay's solution to exposing Id's where there is no natural key in the entity.
This approach maintains DDD & HATEOAS at the cost of going against advice on bi-directional relationships.
Thoughts?
It is possible to add _links to resources that are not mapped through repositories. To add an action deleteComment, for instance, you should configure a #Bean like this:
#Bean
public ResourceProcessor<Resource<Comment>> commentProcessor() {
return new ResourceProcessor<Resource<Comment>>() {
#Override
public Resource<Comment> process(Resource<Comment> resource) {
resource.add(linkTo(methodOn(MyCustomController.class).deleteComment(resource.getContent().getId())).withRel("deleteComment"));
return resource;
}
};
}
You should get the link of the action on the Comment object inside the Post

How to properly use Locking or Transactions to prevent duplicates using Spring Data

What is the best way to check if a record exists and if it doesn't, create it (avoiding duplicates)?
Keep in mind that this is a distributed application running across many application servers.
I'm trying to avoid these:
Race Conditions
TOCTOU
A simple example:
Person.java
#Entity
public class Person {
#Id
#GeneratedValue
private long id;
private String firstName;
private String lastName;
//Getters and Setters Omitted
}
PersonRepository.java
public interface PersonRepository extends CrudRepository<Person, Long>{
public Person findByFirstName(String firstName);
}
Some Method
public void someMethod() {
Person john = new Person();
john.setFirstName("John");
john.setLastName("Doe");
if(personRepo.findByFirstName(john.getFirstName()) == null){
personRepo.save(john);
}else{
//Don't Save Person
}
}
Clearly as the code currently stands, there is a chance that the Person could be inserted in the database in between the time I checked if it already exists and when I insert it myself. Thus a duplicate would be created.
How should I avoid this?
Based on my initial research, perhaps a combination of
#Transactional
#Lock
But the exact configuration is what I'm unsure of. Any guidance would be greatly appreciated. To reiterate, this application will be distributed across multiple servers so this must still work in a highly-available, distributed environment.
For Inserts: if you want to prevent same recordsto be persisted, than you may want to take some precoutions on DB side. In your example, if firstname should be unique, then define a unique index on that column, or a agroup of colunsd that should be unique, and let the DB handle the check, you just insert & get exception if you're inserting a record that's already inserted.
For updates: use #Version (javax.persistence.Version) annotation like this:
#Version
private long version;
Define a version column in tables, Hibernate or any other ORM will automatically populate the value & also verison to where clause when entity updated. So if someone try to update the old entity, it prevent this. Be careful, this doesn't throw exception, just return update count as 0, so you may want to check this.

Selecting native collections defined with #ElementCollection from Entities in JPA

Let's suppose we have an Entity of this type:
#Entity
#Table(name="User")
public class User {
#Id
long id;
#ElementCollection
List<String> phones;
}
My goal is to have the complete list of phones, for all users, something like: "SELECT x.phones FROM User x"
I tried to build a Spring Data JPA query of this kind:
#Query("SELECT x.phones FROM User x")
List<String> findAllPhones();
But I get this exception:
org.hibernate.QueryException: not an entity
at org.hibernate.hql.internal.ast.tree.FromElementType.renderIdentifierSelect(FromElementType.java:188)
I had to resort to a native sql query to solve the problem.
Otherwise I have to wrap the phone number inside a new Entity, but I exactly want to avoid that.
Is there any way to solve this kind of problem using plain JPA or (even better) only Spring Data JPA methods?

How to retrieve nested data in JPQL?

working with OpenJPA2 persistence. I have a very simple entity class, that does have a String property and a List property. I do persist its instances flawlessly with the nested List (in a JSF2 web project). I check the database and there appears two tables (I use automatic schema generation), one for the entity itself, and other table for the nested List. All data persisted using EntityManager is stored fine on both tables.
Problem is I cannot retrieve nested data. I mean, I do a Query for getting all instances of the entity, but the List of all instances come empty.
(DB Engine is MySQL. ORM is OpenJPA2. Server is TomEE 1.6. IDE is Netbeans 8. I use automatic schema generation, so I DO NOT WANT to design the database tables, and I DO WANT to let the ORM create the tables, so I can work purely with objects and forget about DB.)
following is Entity Class code:
#Entity
public class Cliente implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nombre;
#ElementCollection
private List<String> emails = new ArrayList<String>();
// getters and setters omitted for brevity.
It does have an associated Facade Class, which is ClienteFacade. It includes the getAll method which uses a JPQL Query.
public List<Cliente> listaClientes(){
Query query = em.createQuery("SELECT c FROM Cliente c");
return query.getResultList(); }
Problem is, I get all instances of the entity in a List, but all lists of List emails come out empty. I think problem may be in the JPQL query. Still trying to learn JPQL with some difficulty... so please, How can I retrieve the nested data with JPQL?
Many thanks!
Try #ElementCollection(fetch = FetchType.EAGER) because the default type is lazy. That means that the lists are not loaded directly.

Difference between defining queries in the repository interface or entity class?

Sorry if this is a very nooby/stupid question, but I was wondering if there was any difference, besides implementation, between defining a query in the repository:
public interface EmployeeRepository<Employee, Integer> {
#Query("select e from Employee e where e.name like :name")
public List<Employee> findByName(#Param("name") String name);
}
and defining a query in the entity:
#Entity
#NamedQuery(name="Employee.findByName", query="select e from Employee e where e.name like :name")
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
//...
}
Like are there advantages/disadvantages to either one?
Generally speaking we recommend defining the queries at the repository interface for a very simple reason: it's conceptually closer to the query execution. Also, #Query has a few advanced options when it comes to the additional queries that e.g. need to be triggered to implement pagination.
However, if you want to re-use the query definition on multiple query methods, using a named query is still a reasonable option.
The most important aspect IMO is consistency either among the team or at least per repo. If you start with named queries, don't mix them up with #Query definitions as that might confuse developers or at least make it harder to understand what's going on.