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.
Related
According to the Hibernate docs, MappedSuperclass allows mapping inheritance, where the super class is not treated as an entity, and where polymorphic queries that fetch objects by the base class are not supported.
On the other hand, the table per class strategy is similar in terms of the generated schema in the DB, except that it maps the super class to a table if it is not an abstract. However it supports polymorphic queries.
My question is: why would anyone use the #MappedSuperclass strategy? Is there a performance issue implied if the parent class is treated as an entity? Any ideas around this is appreciated.
#MappedSuperclass
By default, properties of the superclass are ignored and not persistent!
You have to annotate the superclass with #MappedSuperclass to enable embedding of its properties in the concrete subclass tables.
You can override column mappings from the superclass in a subclass with the #AttributeOverride annotation or several with #AttributeOverrides.
You could declare the identifier property in the superclass, with a shared column name and generator strategy for all subclasses, so you wouldn’t have to repeat it. But it’s optional!
The main problem with implicit inheritance mapping is that it doesn’t support polymorphic associations very well. In the database, you usually represent associations as foreign key relationships. If the subclasses are all mapped to different tables, a polymorphic association to their superclass can’t be represented as a simple foreign key relationship.
Polymorphic queries that return instances of all classes that match the interface of the queried class are also problematic. Hibernate must execute a query against the superclass as several SQL SELECTs, one for each concrete subclass.
A further conceptual problem with this mapping strategy is that several different columns, of different tables, share exactly the same semantics. This makes schema evolution more complex. For example, renaming or changing the type of a superclass property results in changes to multiple columns in multiple tables. Many of the standard refactoring operations offered by your IDE would require manual adjustments, because the automatic procedures usually don’t account for things like #AttributeOverrides. It also makes it much more difficult to implement database integrity constraints that apply to all subclasses.
So, this approach is a good chose for the top level of your class hierarchy,
where polymorphism isn’t usually required, and when modification of the superclass
in the future is unlikely.
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
The database identifier and its mapping have to be present in the superclass, to share it in all subclasses and their tables. This is no longer optional, as it was for the #MappedSuperclass mapping strategy.
Note that the JPA standard specifies that TABLE_PER_CLASS is optional, so not all JPA implementations may support it. The implementation is also vendor dependent — in Hibernate, it’s equivalent to a <union-subclass> mapping in the old native Hibernate XML metadata.
The advantages of this mapping strategy are clearer if we examine polymorphic queries. The tables are combined with a UNION operator, and a literal is inserted into the intermediate result; Hibernate reads this to instantiate the correct class given the data from a particular row. A union requires that the queries that are combined project over the same columns; hence, you have to pad and fill nonexistent columns with NULL. You may ask whether this query will really perform better than two separate statements. Here you can let the database optimizer find the best execution plan to combine rows from several tables, instead of merging two result sets in memory as Hibernate’s polymorphic loader engine would do.
Another much more important advantage is the ability to handle polymorphic associations. Hibernate can use a UNION query to simulate a single table as the target of the association mapping.
So, this approach is a good chose when you need to use polymorphic queries and associations.
P.S. This is almost verbatim quotation from the excellent book: Java Persistence with Hibernate (Bauer, King, Gregory)
meaning a class whose mapping information is applied to the entities that inherit it.
I'm designing a solution for dealing with complex structure (user related stuff with lots of relations) in a simplier and possibly more efficient way than getting all the related data from DB. The only part of data I really need in my use case is basically contained withing the non-relational 'main' entity fields.
As for now I extracted the basic fields from 'main' class (let it be class OldMain) to another class (let's call it abstract class Extracted), used #MappedSuperclass and created 2 classes that extends it- Basic (which is empty class as Extracted gives it all the data I need and mapped to table 'X') and Extended (which is also mapped to table 'X' but with all the extra relations). It basically works but the code structure looks odd and makes me thinking if that's a proper way of dealing with such a problem.
I also tried with lazy initiation on relational fields (which i guessed on the beginning would serve here well), but I wasn't able to get it to work as I wanted with Jackson (only non-lazy fields in JSON, without fetching lazy related data- it couldn't be serialized or fired another several dozen of relation queries).
Another thing i stumbled upon in some tutorial was making DTO from 'OldMain' entity to not touch the lazy fields but haven't tried it yet as I started with the #MappedSuperClass way.
#Table(name = "X")
#MappedSuperclass
public abstract class Extracted{
//all the non-relational fields from OldMain
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String surname;
private String userName;
private String email;
}
#Table(name = "X")
#Entity
public class Basic extends Extracted{
//empty
}
#Table(name = "X")
#Entity
public class Extended extends Extracted{
//all relational fields from OldMain, no data fields
}
Also the general question is- is there any good practices when dealing with need of using only a subset of a bigger entity?
There is no obligation for a JPA Entity to map all existing columns in the corresponding table in the database. That is, given a table my_entity with columns col1, col2, col3, the Entity mapped to this table could map only col1 and col2 and ignore col3. That being said, plus the fact that you only need the non-relational attributes, you could directly use your Extracted class with the attributes you need and ignore the fact that other relational field exists. Furthermore, if all the relational fields are nullable then you could even be able to persist new instances of Extracted class. And Jackson would only (un)marshal the declared attributes in Extracted class.
In other case, I suggest to follow the approach you already are in and define new Entity classes that extend your Extracted class with the required attributes. I don't see how "code structure looks odd", other than having a Basic class with no new attributes than Extracted - you could easily make Extracted non-abstract and use it directly, and get rid of Basic.
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 use JPA 2 with Hibernate. There are two entity classes, CardElement and IdentityDocumentKind. The last one is an inherited entity of the first one. SINGLE_TABLE inheritance strategy is used. When I try to select an instance of the parent class by query from CardElement where id = '123456' the following error occures:
Object with id: 123456 was not of the specified subclass:
org.cp.cardsystem.CardElement (Discriminator: SDocClass)
I don't have a subclass for "SDocClass" discriminator value. Actually at the moment of developing IdentityDocumentKind class querying of CardElement was used widely across the application. So I can't create a subclass of CardElement for each discriminator value and replace CardElement with it in all existent queries. It would be cost too much efforts for me. Is there a way to instantiate parent entity class when SINGLE_TABLE inheritance strategy is used?
I am not sure if I understand your problem correctly. You are using Single Table strategy to store the whole inheritance hierarchy. However, you have only mapped some of the discriminators, and this time, it is the unmapped discriminator causing the problem (because Hibernate dunno what that subclass means). Am I understanding your problem correctly?
Consider work against a special DB view instead of the real table. That view expose only records with discriminator you can handle.
Problem is solved. I've annotated root entity class of inheritance hierarchy (CardElement) in this way: #DiscriminatorValue(value = "not null"). Now I can select objects of this class without creating subclass for each discriminator value. not null and null seem to be Hibernate's special discriminator values which match in discriminator column anything except null and null respectively. I've not found any information about these values in Hibernate's official documentation. So it could be some kind of undocumented feature.
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()?