I have entities:
#Entity
public class C {
#Column
private String name;
}
#Entity
public class B {
#Column
private Integer id;
#ManyToOne
#JoinColumn(name = "id_c")
private C c;
}
#Entity
public class A {
#OneToMany(mappedBy = "a")
#OrderBy("id")
private Set<B> itemsB;
}
Now when i access to A.itemsB() - items ordered by B.id
I need to get A.itemsB() ordered by C.name. Is this possible?
I tried to write something like #OrderBy("c.name") but it not work.
just check wich Order is imported : org.hibernate.annotations.OrderBy or javax.persistence.OrderBy.. you should use the second.
You should not use a 'Set<B>', but a 'List<B>'.Sets are always unordered.
Related
I would like to use the EntityGraph Feature because of the known n+1 Problem. I have the following Entities structure:
#Entity
#Table(name = "customer")
public class Customer extends Person {
#Column(name = "foo")
public String foo;
#Column(name = "bar")
public String bar;
}
#Entity
#Table(name = "person")
public class Person {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "car.id")
public Car car;
#Embedded
public Key key;
}
#Entity
#Table(name = "car")
public class Car {
#Column(name = "a")
public String a;
#Column(name = "b")
public String b;
}
#Embeddable
public class Key
{
#Column(name = "key_id")
public Long keyId;
#Column(name = "key_color")
public String keyColor;
}
Now I want to use a NamedEntityGraph. As far as I understand with "#NamedEntityGraph(name = "getCustomer", includeAllAttributes=true)" it should work but it doesnt.
The NamedEntityGraph call with
em.createQuery(criteriaQuery).setHint("javax.persistence.fetchgraph", em.getEntityGraph("getCustomer")).getResultList()
returns the amount of Customers in the database but all Attributes including car and the Embedded Attribute key is always null.
Do I have to use subgraphs? I tried to declare the NamedEntityGraph on Customer class also on Person class. It makes no difference.
EDIT:
After struggling a long time with this problem, i tried to break down it to the lowest level with these two entities
#Entity
#Table(name = "publication")
#NamedEntityGraph(name = "graph.Publication.articles",
attributeNodes = #NamedAttributeNode("articles"))
public class Publication {
#Id
private String publicationId;
private String name;
private String category;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "publicationId")
private List<Article> articles;
#Entity
#Table(name = "article")
public class Article {
#Id
private String articleId;
private String title;
private String publicationId;
}
If i create a query i can see further more than one query in the postgres log.
EntityGraph<?> entityGraph = em.getEntityGraph("graph.Publication.articles");
List resultList = em.createQuery("SELECT x FROM Publication x").setHint("javax.persistence.fetchgraph", entityGraph).getResultList();
Different queries for all publications
SELECT ARTICLEID, publicationId, TITLE FROM article WHERE (publicationId = $1) parameters: $1 = 'publication_1'
SELECT ARTICLEID, publicationId, TITLE FROM article WHERE (publicationId = $1) parameters: $1 = 'publication_2'
But I would only have expected one query with a join here.
Finally I found a solution for my problem. I refer to the edited part of my question.
I found this page which describes very well how to use batch query hints to improve performance.
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html?m=1
For my example I don't need the entitygraph anymore. The query should created like this
List resultList = em.createQuery("SELECT x FROM Publication x").setHint("eclipselink.batch", "x.articles").getResultList();
I am trying to use #ElementCollection with a set of classes which are all inherited from a #MappedSuperclass but when persisting to the database there is no column to identify which subclass was created and therefore will fail when trying to retrieve it from the database. If I change the class to make it an entity instead it will then work but I need it to be #Embeddable to work with #ElementCollection
Below is the code:
#Entity
public class A {
private String attr1;
private String attr2;
....
#ElementCollection
private List<B> list;
....
}
Superclass:
#Embeddable
#MappedSuperclass
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class B {
private String attr3
private String attr4
....
}
Subclass1:
#Embeddable
#DiscriminatorValue("B1")
public class B1 extends B {
private String attr5
....
}
Subclass2:
#Embeddable
#DiscriminatorValue("B2")
public class B2 extends B {
private String attr6
....
}
Thanks in advance
#ElementCollection is for basic or embeddable values which both have no concept of inheritance. If you want inheritance, you need to model the value as entity and then use #OneToMany. From a relational mapping perspective, the two mappings are almost the same:
#Entity
public class A {
private String attr1;
private String attr2;
....
#OneToMany(mappedBy = "a")
private List<B> list;
....
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class B {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private A a;
private String attr3
private String attr4
....
}
Lets assume we have a complex JPA relation, a fraction of which looks like this:
#MappedSuperclass
public class DiffEntity {
private String diffId;
public DiffEntity() {
this.diffId = UUID.randomUUID().toString();
}
//...
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class ParentEntity extends DiffEntity {
#Id
#GeneratedValue
private long id;
#Column
private String name;
//...
}
#Entity
public class Construct extends ParentEntity {
#Column
private String variable;
#OneToMany(mappedBy = "construct", cascade = CascadeType.ALL)
private List<Partconstruct> partconstructs;
//...
}
#Entity
public class Partconstruct extends ParentEntity {
#OneToMany(mappedBy = "partconstruct", cascade = CascadeType.ALL)
private List<Field> fields;
#OneToMany(mappedBy = "partconstruct", cascade = CascadeType.ALL)
private List<Hardparameter> hardparameters;
#ManyToOne
#JoinColumn(name = "construct_id")
private Construct construct;
//...
}
#Entity
public class Field extends ParentEntity {
#Column
private int fieldSize;
#ManyToOne
#JoinColumn(name = "partconstruct_id")
private Partconstruct partconstruct;
//...
}
#Entity
public class Hardparameter extends ParentEntity {
#Column
private String value;
#ManyToOne
#JoinColumn(name = "partConstruct_Id")
private Partconstruct partConstruct;
//...
}
We are concerned with Construct type objects. Construct is deeply cloned and persisted, having all its nested objects on the object graph being cloned too and getting a new Id (primary key). On every clone the diffId (from DiffEntity entity) stays the same (it serves the purpose of correlating objects for a diffing feature).
How would it be possible to search and get a reference for a specific DiffEntity given we have the below:
a reference to the Construnct instance
type of the nested object
diffId we are after.
I have tried different versions of object graph traversers with reflection, which will work for a small in size Construct object, but once it becomes too big performance is very slow.
Is there any magic on the entity manager itself to achieve that ?
So I understand how to use the JPA/Hibernate filters for immediate sub properties ( demonstrated here: annotation to filter results of a #OneToMany association ) but what I want to do is use a nested property for excluding a reference. So if C is not active as a reference of B, I do not want B included in the set. Here is an example of code that does not work. It complains about c.Active being unknown in there where column. That is because the sql generated contains c_0.is_active as the reference. Is there a way to do something like this?
#Entity
public class A implements Serializable{
#Id
#Column(name = "REF")
private int ref;
#OneToMany
#JoinColumn(name = "A_REF", referencedColumnName = "REF")
#Filter(name="test")
private Set<B> bs;
}
#Entity
#FilterDef(name="test", defaultCondition="c.ACTIVE = 1")
public class B implements Serializable{
#Id
#Column(name = "A_REF")
private int aRef;
private C cObject;
}
#Entity
public class C implements Serializable{
#Id
private int ref;
#Column(name = "ACTIVE")
private boolean active;
}
I dont think you can use references to other tables this way.
Try this:
#Entity
#FilterDef(name="test", defaultCondition="aRef =
(select b.aRef
from B b inner join C c on c.ref = b.cRef
where c.ACTIVE = 1)"
public class B implements Serializable{
I want to model a couple of object relations and I'm currently not sure about a smart way to do this. Let's assume a Record has a OneToMany relationship to different RecordSources. The common attributes of the RecordSources are long id and boolean preferred. Other attributes are individual and the number of record sources may increase in the future.
One possibility is for Record
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="record")
private List<GenericSimpleRecordSource> recordSources;
where GenericSimpleRecordSource would look like this:
#Entity
public class GenericSimpleRecordSource implements Serializable
{
public static enum Type {a,b}
#ManyToOne private Record record;
#NotNull
private Type sourceType;
#OneToOne(cascade = CascadeType.ALL,mappedBy="source")
private SimpleRecordSourceA sourceA;
#OneToOne(cascade = CascadeType.ALL,mappedBy="source")
private SimpleRecordSourceB sourceB;
}
SimpleRecordSourceA and SimpleRecordSourceA are individual #Entity classes. I don't feel comfortable with this approach, using inheritance might be better:
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
#DiscriminatorColumn(name="type")
#DiscriminatorValue("generic")
public class GenericRecordSource
{
#Id #GeneratedValue(strategy=GenerationType.AUTO) private long id;
#ManyToOne private Record record;
private boolean preferred;
}
#Entity
#DiscriminatorValue("A")
public class RecordSourceA extends GenericRecordSource
{
...
}
#Entity
#DiscriminatorValue("B")
public class RecordSourceB extends GenericRecordSource
{
...
}
This seems to be smarter, but are there any shortcomings using Inheritance? I appreciate any comments on both approaches or even another alternative.
Is it possible to model the #OneToMany relationship from Record like this?
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="record")
private List<GenericRecordSource> recordSources;