Can I use CompositeId on subclasses of Discriminated Entity Hierarchy? - java

I have a entity hierarchy has single table for all subclasses strategy. And I want to use each properties - mapped #ManyToOne - as primarykey. When I put #Id annotation, I'm getting this error:
java.lang.ClassCastException: org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass
So how can I provide to define all properties as identifier on discriminated hierarchy?

Your ID needs to be unique for the highest object in the hierarchy that is an entity. You can't define ID on subclasses and have an superclass, that is an entity, that has no ID.
Think of it this way, entityManager.find(SuperClass.class, 2); is a perfectly legal call. If ID were defined on subclasses as an FK column, more than one of them could have ID 2! What would be returned?
Using the FK side of a ManyToOne relationship as a primary key is nonsensical in the first place. It would by definition be a OneToOne then.

Related

Schema design for inheritance strategy Table Per Class

I am trying to design a database schema so that it is applicable for the Hibernate's Table Per Class inheritance strategy. So, I will not let Hibernate to generate the tables, instead I need to design them myself in Liqibase but in such way that Hibernate can use them with that strategy.
My entity classes should look like this.
Vehicle.java
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Vehicle {
#Id #GeneratedValue
private int id;
private String name;
private String brand;
}
Car.java
#Entity
public class Car extends Vehicle {
private String oil;
}
Bike.java
#Entity
public class Bike extends Vehicle {
private String frame;
}
Now, I know that that this strategy means that all the fields are in all tables, but I am not sure about two things.
1) Do I need to include the ID in the derived tables?
2) Do I even need a Vehicle table in the DB, since it will actually never be used as an entity (rather just an abstract class)?
I'd appreciate if someone could clear that for me.
Now, I know that [the table-per-concrete-class] strategy means that all the fields are in
all tables,
Well no, you seem to be confused. With InheritanceType.TABLE_PER_CLASS, each concrete entity class E maps to a table that contains columns corresponding to all the fields of E, including inherited ones, but not including fields of entities that are not superclasses of E.
This is to be contrasted with InheritanceType.SINGLE_TABLE, in which all entity types in a whole inheritance hierarchy map to the same table, which then necessarily contains a column for each property of each entity in the hierarchy (without duplicating inherited fields).
Note also that it is odd that your Vehicle entity contains fields with the same names as fields of its subclasses. Java fields are not polymorphic, so this is unlikely to be what you want. It's certainly unnecessary.
but I am not sure about two things.
1) Do I need to include the ID in the derived tables?
Supposing that you stick with TABLE_PER_CLASS, yes, each entity table needs to provide a column for each persistent property of the corresponding entity class, including those inherited from superclasses. That includes id.
2) Do I even need a Vehicle table in the DB, since it will actually
never be used as an entity (rather just an abstract class)?
Not if you actually declare it abstract, but if you leave it concrete, then yes, you need a table for it. And that makes sense, because in that case you could have Vehicle entities that are neither Cars nor Bikes.
Hibernate schema generation tool should be able to generate your schema if you annotate your entities correctly.
In this case Vehicle table which be generated since your entity class is concrete. You need to define the class as abstract.
All the fields defined in the superclass (including the #Id) will be copied in the corresponding child class tables. There is a limitation though regarding id auto generation. You cannot use the table per class inheritance strategy with the GenerationType.IDENTITY strategy since the generated keys should be unique across all tables. Identity creates unique ids per table
Make sure the Generation.AUTO strategy does not map to the IDENTITY strategy for your RDBMS (You can specify a strategy explicitly eg GenerationType.TABLE to override the default)

ORM - ManyToMany relation on MappedSuperclass

I have a classes as follows:
AnimalClass [Id, Name, Set<Tag>]
|
+-- FishClass [FishSpecific]
+-- MammalClass [MammalSpecific]
Tag [Name]
So any animal can have any number of associated tags.
For that I use in AnimalClass:
#JoinTable(name="Animal_Tag")
#JoinColumn(name="animal_id", referencedColumnName="id", nullable=false)
#OneToMany(cascade=CascadeType.ALL)
#Getter
protected Set<Tag> tags = new HashSet<Tag>();
My problem is that, Hibernate creates the m-n table as:
Animal_Tag [FishClass_id, MammalClass_id, Tag_id].
I would prefer to have some kind of enumeration as:
Animal_Tag [Animal_id, AnimalTypeEnumeration[ Fish | Mammal ], Tag_id].
Thanks!
The table structure that you want would have a foreign key that can point to different tables, depending on the value of another field. I don't think any DB allows that.
Polymorphism with ORM is always tricky. Best thing to do is just avoid it if you can. Otherwise, maybe you could use #Inheritance(strategy=InheritanceType.JOINED) on Animal? This would result in a table structure like this:
TABLE Animal
- id (primary key)
TABLE Fish
- id (foreign key -> Animal)
- fins
- scales
TABLE Mammal
- id (foreign key -> Animal)
- mammaries
I suspect you can't do that with a mapped superclass.
The thing about a mapped superclass is that it doesn't define a persistent type. It defines a sort of template for a persistent types. Every time you define a subclass of it which is annotated #Entity, you create an instance of the template, but in the data model, there is no relationship between those types. The use of the mapped superclass is almost a shortcut for a copy-and-paste of a given set of fields into the new entity class.
So, as far as the data model is concerned, there is no possible animal_id, because there is no such type as animal. Only fish and mammal exist in the database.
Can you make AnimalClass an entity instead of a mapped superclass? If you use the table-per-class inheritance strategy, you won't need to create a table for it. But it will make animal a type, which means the ORM will be able to use an animal_id.
May be use "table per subclass wih discriminator" inheritance for AnimalClass? In case of hibernate it result fowing hirecaly:
AnimalClass [Id, AnimalTypeEnumeration (discriminator), Name]
|
+-- FishClass [FishSpecific]
+-- MammalClass [MammalSpecific]
Animal_Tag [Animal_id, Tag_id]

Hibernate - referencing abstract entity defined with <union-subclass>

I have an abstract entity A which has several union-subclasses. A.id generator was set to hilo (identity does not work). The other entity, B references this A entity as one-to-many (say, B.setOfA). Now if I try to persist an instance of B I get the following SQL error:
user lacks privilege or object not found: A
That's understandable since A doesn't generate any DDL during hbm2ddl. But I need to do exactly that -- polymorphic reference using abstract entity. How would I achieve that?

bidirectional one-to-one relationship (mappedBy)

You create a bidirectional one-to-one relationship using fields on
both classes, with an annotation on the child class's field to declare
that the fields represent a bidirectional relationship. The field of
the child class must have a #Persistent annotation with the argument
mappedBy = "...", where the value is the name of the field on the
parent class. If the field on one object is populated, then the
corresponding reference field on the other object is populated
automatically.
What can a bidirectional one-to-one relationship do?
Can someone give me a example?
And why I always got this error.
Class "com.example.datastore.Employee" has field "contactInfo" with
"mapped-by" specified as "contactInfo". This field doesnt exist in the
target of the relation ("com.example.datastore.ContactInfo")!!
Thanks in advance!
I try to answer from what I learnt from Hibernate/JPA (which I think is similar)
Seems that your ContactInfo do not have relationship to Employee. To use what you described as an example for bidirectional one-to-one relationship, you will see something like (it is probably not syntactically correct, just to give u idea):
public class Employee {
//... other relationship or fields
#OneToOne(mappedBy="employee") // the field in ContactInfo
private ContactInfo contactInfo;
}
public class ContactInfo {
#OneToOne
#JoinColumn("EMP")
private Employee employee;
}
The 'real' relationship in persistence layer is in fact dominated by ContactInfo.employee. Setting Employee.contactInfo will not cause persistence layer to contain correct data.
I wish this help and applies to JDO too. :P
It sounds like you have a one-to-one of Employee to ContactInfo. An employee has exactly one contact info, and a contact info belongs to exactly one employee. That's a bidirectional one-to-one. Your error is occurring because "mapped-by" needs to specify the name of the property of the other object that refers back to this one. For example, if you have
class Employee {
private ContactInfo contactInfo;
}
class ContactInfo {
private Employee employee;
}
then when you map the Employee.contactInfo property, its "mapped-by" would be "employee" because that's the property that it's "mapped by" in the ContactInfo.
First the Error What the error is saying is that contactInfo is not a field of class com.example.datastore.ContactInfo . They field mapped by must be a field\property of the class you are mapping to .
Second The concept of Bi-Direction Mapping
It's just that two tables in one-to-one or one-to-many relationship where both entities will have knowledge of the other s. You do not always need it and that depends on situation and context but generally is more common to have bi-directional one to many than one to one.
You question is about one-to-one so to give you an example of when both entities need to know about each other from Hibernate docs A bidirectional one-to-one association on a join table is possible, but extremely unusual. But if you really wanted to be able to get either entiy from which ever table (which is very rare) then you create bi-directional one to one
Person and Address just to quote an example

Where to put hibernate annotations?

Where do i put my hibernate annotations?
Is it the line above my instance variable? Or before the getter? Or before the setter? Or doesn't it really matter?
Thanks a lot
You place them either on the field or on the getter. From the Hibernate Annotations Reference Guide:
2.2.1. Marking a POJO as persistent entity
(...)
Depending on whether you annotate
fields or methods, the access type
used by Hibernate will be field or
property. The EJB3 spec requires that
you declare annotations on the element
type that will be accessed, i.e. the
getter method if you use property
access, the field if you use field
access. Mixing annotations in both
fields and methods should be avoided.
Hibernate will guess the access type
from the position of #Id or
#EmbeddedId.
You might also want to read about the #Access annotation that allows to force/override the access type (prior to Hibernate Annotations 3.5 and JPA 2.0, it was part of Hibernate Annotation Extensions):
2.2.2.2. Access type
By default the access type of a class
hierarchy is defined by the position
of the #Id or #EmbeddedId annotations.
If these annotations are on a field,
then only fields are considered for
persistence and the state is accessed
via the field. If there annotations
are on a getter, then only the getters
are considered for persistence and the
state is accessed via the
getter/setter. That works well in
practice and is the recommended
approach.
Note
The placement of annotations within a class hierarchy has to be consistent
(either field or on property) to be
able to determine the default access
type. It is recommended to stick to
one single annotation placement
strategy throughout your whole
application.
However in some situations, you need
to:
force the access type of the entity hierarchy
override the access type of a specific entity in the class hierarchy
override the access type of an embeddable type
The best use case is an embeddable
class used by several entities that
might not use the same access type. In
this case it is better to force the
access type at the embeddable class
level.
(...)
Regarding the pros and cons of both styles, I suggest to read the following questions:
Hibernate/JPA - annotating bean methods vs fields
Hibernate Annotations - Which is better, field or property access?
Performance difference between annotating fields or getter methods in Hibernate / JPA
It's up to your style. You may put it before the field or before getter. In strict JPA, the annotations on setters are ignored, but I'm not sure if Hibernate follows that.
You either need to be consistent throughout your Entity, or you need to provide an #Access annotation at the top of the class with a default mode, and another #Access before each field/property you wish to deviate from the current class mode.
Hibernate is known to use Java reflection. So it really doesn't matter whether you put it above the filed or above the getter.
Here is the description of some important annotation used in Hibernate.
#Entity: declares the class as an entity (i.e. a persistent POJO class)
#Table: is set at the class level; it allows you to define the table, catalog, and schema names for your entity mapping. If no #Table is defined the default values are used: the unqualified class name of the entity.
#Id: declares the identifier property of this entity.
#Generated Value: annotation is used to specify the primary key generation strategy to use. If the strategy is not specified by default AUTO will be used.
#Column: annotation is used to specify the details of the column to which a field or property will be mapped. If the #Column annotation is not specified by default the property name will be used as the column name.
Annotations based Inheritance mapping in Hibernate:
There are three kinds os inheritance mappings in hibernate.
They are
1.Table per Class hierarchy:
#Inheritance – Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.
#DiscriminatorColumn – Is used to define the discriminator column for the SINGLE_TABLE inheritance mapping strategies. The strategy and the discriminator column are only specified in the root of an entity class hierarchy or sub hierarchy in which a different inheritance strategy is applied
If the #DiscriminatorColumn annotation is missing, and a discriminator column is required, the name of the discriminator column defaults to "DTYPE" and the discriminator type to DiscriminatorType.STRING.
#DiscriminatorValue – Is used to specify the value of the discriminator column for entities of the given type. The DiscriminatorValue annotation can only be specified on a concrete entity class. If the DiscriminatorValue annotation is not specified and a discriminator column is used, a provider-specific function will be used to generate a value representing the entity type. If the DiscriminatorType is STRING, the discriminator value default is the entity name.
2.Table per sub Class hierarchy:
#InheritanceType – Defines inheritance strategy options. JOINED is a strategy in which fields that are specific to a subclass are mapped to a separate table than the fields that are common to the parent class, and a join is performed to instantiate the subclass.
#PrimaryKeyJoinColumn – This annotation specifies a primary key column that is used as a foreign key to join to another table.
3.Table per Concrete class hierarchy:
#InheritanceType – Defines inheritance strategy options. TABLE_PER_CLASS is a strategy to map table per concrete class.
#AttributeOverrides – This annotation is used to override mappings of multiple properties or fields.
#AttributeOverride – The AttributeOverride annotation is used to override the mapping of a Basic (whether explicit or default) property or field or Id property or field.
Hope it help's to get idea on basic annotation used in hibenate.

Categories