I have a parent class Party and a subclass LiveParty along with others (see below) and this is always a one to one relationship in the database. Whenever I use the Criteria API it does a Left Outer Join between the two. I want to force an Inner Join between the parent and child as this affects performance for some queries but can't find a way to do this in the documentation, can anyone suggest a way?
#Entity
#Table(name = "Party", schema = "dbo")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Party{
...
}
#Entity
#Table(name = "LiveParty", schema = "dbo")
#PrimaryKeyJoinColumn(name = "partyId")
public class LiveParty extends Party {
...
}
Whenever I use the Criteria API it does a Left Outer Join between the two.
That's indeed what you'll get when using a JOINED strategy, Hibernate will perform an outer join on all the tables corresponding to descendants of a given node of the inheritance tree in order to deduce and return the actual type for a given row (see this great previous answer by ChssPly76 for details).
In other words, I don't think you can force Hibernate to use an inner join, at least not without changing the mapping (using a secondary table or a OneToOne relation, I'm not sure what your constraints are exactly).
Related questions
Hibernate Inheritance Strategy and Why
How does the JPA handle partial, non-disjoint inheritance (using InheritanceType.JOINED in class-per-table scenario) along with EntityManager.find()?
Related
I'm struggling to identify the right annotations to use to map a star schema with Spring Boot JPA.
Let's consider 3 tables:
DIM_One (1)--------(1..n) FACT (1..n) ------------ (1) DIM_Two
DIM_One and DIM_Two both have an id that is their primary key.
FACT's primary key is the combination of (DIM_One_pk, DIM_Two_pk)
For now, the annotations in my DIM tables are similar to :
#Table(name="DIM_One")
#Entity
#Getter
#ToString
public class One {
#Id
#Column(name = "dim_one_id")
private UUID id;
//...
}
As for the FACT table, I have :
#Entity
#Table(name = "FACT")
#ToString
#Getter
public class Fact {
#EmbeddedId
private FactId id;
//...
}
with the corresponding FactId class :
#Embeddable
#Getter
#EqualsAndHashCode
public class FactId implements Serializable {
private One one;
private Two two;
}
I feel a bit lost with the right annotations I would need to use to make it correspond to the cardinality:
DIM_One (1)--------(1..n) FACT (1..n) ------------ (1) Dim_Two
Furthermore, should it actually be mapped as OneToMany or OneToOne ?
Your diagram shows the (1..n)---(1) relationship so it should be mapped like this.
Other then that you need to think about how you want to use this:
If loading a fact, do you want to load the associated dimension entries? This leads to the decision between eager and lazy loading.
Do you want to be able to navigate from fact to dimension or the other way round? Or both? This leads to the decision about directionality.
If you persist, delete ... a fact should dimensions join in that operation? => cascade configuration.
Note: While in principle this should work without major problem, since a star schema is still just a bunch of tables it sounds like a really bad idea.
Star schema are used for large amounts of data and are highly denormalised in order to optimise for reads and aggregations.
This means updates typically hit from a few hundred rows to many thousands, possibly millions.
JPA is not build for this kind of operation and will perform horrible compared to specifically taylored SQL statements.
On the read side you'll constantly operate with aggregate functions and probably windowing functions with non trivial expressions. JPQL, the query language of JPA again is not build for this and will severely limit your options.
Is there any way to force hibernate to use an inner-join for an association using annotations? I am using Hibernate 5 via Spring Boot JPA
#Data
class Entity {
private Integer id;
#OneToMany
#JoinColumn(name="entityId", referencedColumnName="id")
private Set<ComplexObject> complexObjects;
I would like the join for complexObjects be an inner-join rather than a left join.
You shouldn't see a join by default at all since this is a #OneToMany association which is lazy by default. There must be a query explictly using LEFT JOIN FETCH or just LEFT JOIN. Other possible reasons for left joins to happen are the use of an entity graph or the use of the fetch method in the JPA CriteriaBuilder API.
In general, the left join here is correct as it is necessary to retain the expected cardinality. Fetching with an inner join would eliminate the main entity if there were no children which is probably not what one would expect when applying e.g. an entity graph.
I don't understand why you need an INNER JOIN, but depending on how the join is created, you might have to adapt your query to get the desired result.
In my Spring application I have an entity called Resource::
#Entity
public class Resource {
List<Resource> list = em.createNativeQuery("select r.* from ...", Resource.class).getResultList();
For one specific purpose, I need a few more fields to be added to the results. So I created a subclass ExtendedResource:
#Entity
public class AreaResource extends Resource {
#Column(name="extra_field")
private Integer extra field;
List<ExtendedResource> list = em.createNativeQuery("select extra_field, r.* from ...", ExtendedResource.class).getResultList();
This works fine when I query for ExtendedResource, but for Resource I get:
org.postgresql.util.PSQLException: The column name DTYPE was not found in this ResultSet.
Is there any way around this, without bothering with a discriminator column? I guess MappedSuperclass is a solution, but I would like to avoid making extra classes.
Thanks
A trivial problem, but no way around it without some coding :)
Other than creating a #MappedSuperclass (which, as you said, is a solution), or creating an entity hierarchy (with DTYPE), you could call em.createNativeQuery(sql) without the resulting class, which would give you the result in the form of List<Object[]>. Then, for each row create a new instance of ExtendedResource in a loop. If you go for this option, make sure you specify all the columns one by one instead of using *, to ensure the order in which they are returned.
This way, you might even create a #Transient extra field in the Resource class, and eliminate the need for additional class.
It's just a matter of personal preference which of the approaches suites you best. #MappedSuperclass seems to involve the least amount of coding.
I think you're going to have to define the DiscriminatorColumn.
The default strategy, InheritanceType.SINGLE_TABLE, is used if the #Inheritance annotation is not specified on the root class of the entity hierarchy.
With the single table strategy, the entire class hierarchy is persisted in one big single table. A discriminator column is required to differentiate between which class type is persisted in a particular row
The default name of the column to be used as the discriminator column is DTYPE.
https://docs.oracle.com/javaee/6/api/javax/persistence/DiscriminatorColumn.html
https://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html
The solution is:
Add #DiscriminatorValue("0") for the super class.
Add 0 as dtype into select fields.
#Entity
#DiscriminatorValue("0")
public class Resource {...}
List<Resource> list = em
.createNativeQuery("select 0 as dtype, r.* from ...", Resource.class)
.getResultList();
0 is the super class DiscriminatorValue, can change to the value what you want.
I have a question about the performance difference between Integer and String discriminator types.
I am using Joined strategy, namely :
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class SuperClass
and I have some sub classes which are extending this super class.
Which has a better performance? DiscriminatorType.INTEGER or DiscriminatorType.STRING?
Our provider is eclipselink and we are working on a massive volume of data.
Thanks in advance.
Normally using integer fields as the primary key column or index column or join would perform better if that is all you asking about.
But if you are really dealing with massive amount of data you may consider using SINGLE_TABLE instead of JOINED type inheritance if there are not many different attributes on the extending classes.
Because with JOINED type inheritance you need to do a extra join operation every time you need data. And also you should do 2 inserts for every insertion.
Put another way: How do you model/map a heavily reused child class/table to many different parent entities?
I have several entity types each being persisted into its own table:
class A --> table A
class B --> table B
....
Now I need to make each of these classes the parent of a 1:M unidirectional child collection. The collection is a history of approvals the entity has gained over time. The Child domain class is called "ApprovalItem". The Approval class is exactly the same for all types of parents.
What is the best way to map this? If I create a single table to hold all ApprovalItems, then I can't enforce a FK relation to the PK of the entity and/or I am left with a bad database design.
On the other hand, I could create an ApprovalIems table for each entity type (e.g. A_ApprovalItems, B_ApprovalItems, etc.). This seems like a good schema on the database side, but then it seems I need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.). This seems like a lot of hassle and complexity to create so many new classes in Java that do nothing other than allow me to put in different JPA mapping annotations.
Is there a mapping technique in Hibernate that will allow me to have one class in Java map to several different tables depending on who the parent owner of the collection is?
I could create an ApprovalItem table for each entity type (e.g. A_ApprovalItem, B_ApprovalItem, etc.). This seems like a good schema on the database side
But
It seems i need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.).
You do not need it. you can create a single ApprovalItem class and create a #OneToMany relationship between your parent classes and your ApprovalItem. Hibernate takes care to create a linked table for each relationship.
#Entity
public class ClassA {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSA_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
#Entity
public class ClassB {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSB_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
And your ApprovalItem class
#Entity
public class ApprovalItem {
#Id
#GeneratedValue
private Integer id;
// Nothing else
}
But Let's see what Java Persistence with Hibernate book talks about it
You may have shared references to the Bid objects. As suggested earlier, a User may have a collection of references to the Bid instances they made. You can’t delete an item and all its bids without removing these references first. You may get an exception if you try to commit this transaction, because a foreign key constraint may be violated.
So keep it in mind when dealing with shared references.
In order to see how the target schema looks like, you can use the following
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration
.addAnnotatedClass(ClassA.class)
.addAnnotatedClass(ClassB.class)
.addAnnotatedClass(ApprovalItem.class)
.setProperty(Environment.USER, <TYPE_YOUR_USER>)
.setProperty(Environment.PASS, <TYPE_YOUR_PASSWORD>)
.setProperty(Environment.URL, <TYPE_YOUR_URL>)
.setProperty(Environment.DIALECT, <TYPE_YOUR_DIALECT>)
.setProperty(Environment.DRIVER, <TYPE_YOUR_DRIVER>);
SchemaExport schema = new SchemaExport(configuration);
schema.setOutputFile("schema.sql");
schema.create(<DO_YOU_WANT_TO_PRINT_TO_THE_CONSOLE>, <DO_YOU_WANT_TO_EXPORT_THE_SCRIPT_TO_THE_DATABASE>);
It will generate a file called schema.sql, which contains your target schema
regards,
Chapter 8. Inheritance Mapping of Hibernate Documentation might help.
Otherwise, I see no problem having multiple ApprovalItem derived class that "do nothing", like you say, since it does differentiate the Approval, it's like having a type of approval. Seeing your model like so, I would recommend using multiple classes, even if they only inherit from your base ApprovalItem class.
Have I well understood your question or am I missing something else more subtle?