JPA why OrderBy is applied to Set - jpa

JPA why OrderBy is applied to Set?
https://docs.oracle.com/javaee/7/api/javax/persistence/OrderBy.html
#Entity
public class Person {
...
#ElementCollection
#OrderBy("zipcode.zip, zipcode.plusFour")
public Set<Address> getResidences() {...};
...
}
The Set is supposed to be not ordered. Is it meaningful to annotate #OrderBy
on attributes with Set type?

I think the answer marked as checked on this question can answer also yours.
As mentioned there, the annotation "Specifies the ordering of the elements of a collection valued association or element collection at the point when the association or collection is retrieved."
From what I understand, the annotation is not necessarily connected with the order that the elements are inserted on the Collection type that we use in the entity class.

Related

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)

Map two fields to one database column

Question: Am I somehow able to map two fields of my Entity class to only one Column in the Database?
Scenario: The database is not fully normalized. There exists one Column which contains a composite information. It is not my actual use case, but an comprehensible example might be X- and Y-coordinate of a point in the plane. So the Database may contain a String 12:45 and the Entity class should contain only two integer field x width value 12 and ywith value 45.
Currently the Entity class has just two additional getter and setter for x and y and performs the proper translation. But I am wondering if there is a way to let JPA do this for me magically in the background.
I am already working with custom converter classes, e.g. for a proper mapping between between enums and database columns, but this works only for a "one-to-one" mapping between the field in the Entity class and the column in the database.
Of course it would be the most preferable way to redesign the table in the database, but that's not an option at the moment.
Vendor specific solutions are also fine.
2 Entity fields into one database column can be done fairly simply by specifying JPA use your accessor in the entity to handle the conversion:
#Entity
#Access(AccessType.FIELD)
class myEntity {
#Id
int id;
#Transient
String x;
#Transient
String y;
#Mutable //EclipseLink specific to prevent change tracking issues
#Access(AccessType.PROPERTY)
#Column(name="yourDatabaseFieldName")
private String getCoords() {
return x+":"+y;
}
private void setCoords(String coords) {
//parse the string and set x+y.
}
EclipseLink and Hibernate have transformation mappings that are able to handle the reverse; 2 or more database fields into one java property but this is outside of JPA.

JPA oredered lists #OrderedBy and #OrederColumn

I have a question about the #OrderBy and #OrderColumn of the JPA spec.
The problem is that I will have an entity that maintains a list of elemets. Each element will appear in several lists. As I understand the #OrderBy and #OrderColumn annotations, you cannot have the same element appear in different positions in many ordered lists. I just can't believe this.
Can someone explain these annotations a bit? The difference between these two annotations? Specifically how I could do soemthing like this:
#Entity
public class Class{
#ManyToMany
private List<Students> studentsInRankedOrder;
// this list should be ordered by class rank.
// but a student who is ranked 1 in one class will most likely not be ranked 1
// in another course.
}
#Entity
public class Student{
#ManyToMany
private List<Class> enrolledIn;
}
Thanks a lot.
http://openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/manual.html#ref_guide_mapping_jpa_coll_order
I understand now. "Order columns are always in the container table." This makes much more sense to me.

Using Annotations In JPA can I limit child records with a where clause?

I have an EJB with an #onetomany relationship like this in my parent class (Timeslot):
#OneToMany(mappedBy = "rsTimeslots")
private List<RsEvents> rsEventsList;
I also have a function to get the rsEventList:
public void setRsEventsList(List<RsEvents> rsEventsList) {
this.rsEventsList = rsEventsList;
}
This was all auto generated so far. In my view-layer code I can get a timeslot object and do something like timeslot.getRsEventList() and get all children of this timeslot. Now I need to restrict that list based on a criteria. For example I only want events that are children of this timeslot with a status of 1. Is there a way to do this with annotations?
Not in JPA.
Normally you would execute a Query for this, using JPQL or the criteria API.
Some JPA providers do provide ways to restrict relationships, but I think you would be best off with a query, or providing a get/filter method on your class that just accesses the list and filters it (i.e. getStatus1Events()).
For an EclipseLink example of having a criteria on a mapping see,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/MappingSelectionCriteria

Java Persistence API(JPA) - Overriding MappedSuperClass's attributes

I have the following questions
I have the '#Id' annotated field as part of my '#MappedSuperClass' and I am letting all my entities extend the MappedSuperClass.Now,how do I override the super class 'id' if I have to define a composite primary key for my entity...ie.How do I ask my entity to use its composite primary key annotated as #EmbeddedId instead of the #Id annotated field inherited from the MappedSuperClass? Will the #EmbeddedId annotation in my entity automatically over-ride the superclass's #Id ?
I have made a few fields (which are shared by most of the entities in my schema) as part of my MappedSuperClass. Now how do I avoid those fields getting added as columns if few of the entities don't need them ?
Thanks.
[...] How do I ask my entity to use its composite primary key annotated as #EmbeddedId instead of the #Id annotated field inherited from the MappedSuperClass? Will the #EmbeddedId annotation in my entity automatically over-ride the superclass's #Id ?
AFAIK, you can't. So don't inherit from your entity superclass in this case, use another entity superclass.
I have made a few fields (which are shared by most of the entities in my schema) as part of my MappedSuperClass. Now how do I avoid those fields getting added as columns if few of the entities don't need them ?
Well, again, don't inherit from the entity superclass that holds these fields and use another entity superclass.
JPA provides attribute-override to override the mappings for both embedded or mappedsuperclass fields.
For Annotations you can use the #AttributeOverride annotation within the java class.
For multiple attributes you can use the #AttributeOverrides annotation which contains an array of the #AttributeOverride annotation.