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

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.

Related

Is it possible to use SQL syntax like FROM DUAL in JPA?

I am trying to create an independent project regardless of the type of DB using JPQL's #Query .
How do I implement the syntax below in JPA?
SELECT MY_SEQ.NEXTVAL FROM DUAL
Short answer:
For this kind of query, it's more productive to just use nativeQuery = true and use it normally.
To make it database agnostic as you want, you could theoretically just create a DUAL table in the new database.
Long answer:
The short answer is what you are actually looking for. But for the sake of other people who might fall here through Google for other related reasons though, if you really want it, you could theoretically transform Oracle's DUAL table into an entity by using #Subselect like so:
#Table
#Entity
#Subselect("SELECT dummy FROM DUAL")
public class DualEntity {
#Id
#Column(name = "dummy")
private String dummy;
}
Where dummy is the sole column in the DUAL table.
Although this doesn't seem very useful at first glance because most of this kind of queries are much easier to run as native queries, this does let us create repository interfaces for database functions when they aren't related to any actual tables in the database. Example:
#Repository
public interface DualRepository extends JpaRepository<DualEntity, String> {
#Query(nativeQuery = true, value = "SELECT MY_OWNER.MY_FUNCTION(:myParameter) FROM DUAL")
String myFunction(Long myParameter);
}
Which again, this function should probably be part of your code and not part of the database, but older applications tend to have this kind of stuff around. Procedures could also be called through #Query and could also benefit from this kind of mapping.

Simple Tagging Implementation with Spring Data JPA/Rest

I am trying to come up with a way of implementing tags for my entity that works well for me and need some help in the process. Let me write down some requirements I have in mind:
Firstly, I would like tags to show in entities as a list of strings like this:
{
"tags": ["foo", "bar"]
}
Secondly, I need to be able to retrieve a set of available tags across all entities so that users can easily choose from existing tags.
The 2nd requirement could be achieved by creating a Tag entity with the value of the Tag as the #Id. But that would make the tags property in my entity a relation that requires an extra GET operation to fetch. I could work with a getter method that resolves all the Tags and returns only a list of strings, but I see two disadvantages in that: 1. The representation as a list of strings suggests you could store tags by POSTing them in that way which is not the case. 2. The process of creating an entity requires to create all the Tags via a /tags endpoint first. That seem rather complicated for such a simple thing.
Also, I think I read somewhere that you shouldn't create a repository for an entity that isn't standalone. Would I create a Tag and only a Tag at any point in time? Nope.
I could store the tags as an #ElementCollection in my entity. In this case I don't know how to fulfill the 2nd requirement, though.
#ElementCollection
private Set<String> tags;
I made a simple test via EntityManager but it looks like I cannot query things that are not an #Entity in a result set.
#RestController
#RequestMapping("/tagList")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class TagListController implements RepresentationModelProcessor<RepositoryLinksResource> {
#PersistenceContext
private final #NonNull EntityManager entityManager;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<EntityModel<TagList>> get() {
System.out.println(entityManager.createQuery("SELECT t.tags FROM Training t").getFirstResult());
EntityModel<TagList> model = EntityModel.of(new TagList(Set.of("foo", "bar")));
model.add(linkTo(methodOn(TagListController.class).get()).withSelfRel());
return ResponseEntity.ok(model);
}
}
org.hibernate.QueryException: not an entity
Does anyone know a smart way?
The representation as a list of strings suggests you could store tags by POSTing them in that way which is not the case
This is precisely the issue with using entities as REST resource representations. They work fine until it turns out the internal representation (entity) does not match the external representation (the missing DTO).
However, it would probably make most sense performance-wise to simply use an #ElementCollection like you mentioned, because you then don't have the double join with a join table for the many-to-many association (you could also use a one-to-many association where the parent entity and the tag value are both part of the #Id to avoid a join table, but I'm not sure it's convenient to work with. Probably better to just put a UNIQUE(parent_id, TAG) constraint on the collection table, if you need it). Regarding the not an entity error, you would need to use a native query. Assuming that you have #ElementCollection #CollectionTable(name = "TAGS") #Column(name = "TAG") on tags, then SELECT DISTINCT(TAG) FROM TAGS should do the job.
(as a side note, the DISTINCT part of the query will surely introduce some performance penalty, but I would assume the result of that query is a good candidate for caching)

JPA: How to get results by compromised where-clause

I have a table with 30 columns.
I fill the object within my java code. Now I want to look up in my database, if the row is already inserted. I can do this primitive like:
SELECT *
FROM tablename
WHERE table.name=object.name
AND table.street=object.street
AND ...
AND ...
AND ...
I think you get it. It works, but in my opinion this is not the best solution.
Is there any kind of a generic solution (eg: I do not need to change the code, if the table changes), where I can give the where-clause my object and it can match itself? Also the where-clause is not that massive.
The closest thing that comes to mind is the Spring Data JPA Specifications.
You can isolate the where clauses in an instance for a particular entity.
Afterwards, you just pass it to any of the #Repository methods:
public interface UserRepository extends CrudRepository<User, Long>,
JpaSpecificationExecutor<User> {
}
Then in your service:
#Autowired
private UrerRepository repo;
public void findMatching() {
List<User> users = repo.findAll(new MyUserSpecification());
Then, whenever db changes you simply alter one place, which is the Specification implementation.

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

Persisting a list of an interface type with JPA2

I suspect there's no perfect solution to this problem so least worst solution are more than welcome.
I'm implementing a dashboard using PrimeFaces and I would like to persist the model backing it (using JPA2). I've written my own implementation of DashboardModel and DashboardColumn with the necessary annotations and other fields I need. The model is shown below:
#Entity
public class DashboardSettings implements DashboardModel, Serializable{
#Id
private long id;
#OrderColumn( name="COLUMN_ORDER" )
private List<DashboardColumn> columns;
...a few other fields...
public DashboardSettings() {}
#Override
public void addColumn(DashboardColumn column) {
this.columns.add(column);
}
#Override
public List<DashboardColumn> getColumns() {
return columns;
}
...snip...
}
The problem is the columns field. I would like this field to be persisted into it's own table but because DashboardColumn is an interface (and from a third party so can't be changed) the field currently gets stored in a blob. If I change the type of the columns field to my own implementation (DashboardColumnSettings) which is marked with #Entity the addColumn method would cease to work correctly - it would have to do a type check and cast.
The type check and cast is not the end of the world as this code will only be consumed by our development team but it is a trip hazard. Is there any way to have the columns field persisted while at the same time leaving it as a DashboardColumn?
You can try to use targetEntity attribute, though I'm note sure it would be better than explicit cast:
#OrderColumn( name="COLUMN_ORDER" )
#OneToMany(targetEntity = DashboardColumnSettings.class)
private List<DashboardColumn> columns;
Depends on the JPA implementation (you don't mention which one); the JPA spec doesn't define support for interface fields, nor for Collections of interfaces. DataNucleus JPA certainly allows it, primarily because we support it for JDO also, being something that is part of the JDO spec.