JPA / HIBERNATE Entity from two inherited classes - java

Can some one help me with example / idea how to deal with this scenario.
I have class Animal and class Cat , that extend Animal.
In Animal I have some field, also some new field in my Cat class.
So I have to create hibernate entity, that store my Cat in db and somehow to have info about parents field.

use annotation #Inherance
with
strategy=InheritanceType.ONLY_ONE_TABLE (or SINGLE_TABLE)
strategy=InheritanceType.TABLE_PER_CLASS
strategy=InheritanceType.JOINED

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)

ActiveAndroid abstract class table

Does anyone know if it is possible to create a table for an abstract class in ActiveAndroid. For example i could have an abstract class Animal with two concrete classes Dog and Cat. I want to be able to do something like:
List<Animal> animals = new Select().from(Animals.class).execute();
which would result in 'animals' containing all of the saved Cats and Dogs.
Or:
Animal animal = new Select().from(Animals.class).where("name = ?", name).executeSingle();
Where 'animal' could be either a Cat or a Dog.
Unfortunately when I do this I get an exception because no table is created for the abstract class Animal.
Does anyone know how I might go about this using ActiveAndroid?
Unfortunately ActiveAndroid does not support inheritance of models in that way just yet (https://github.com/pardom/ActiveAndroid/issues/14, https://github.com/pardom/ActiveAndroid/issues/257).
If you wanted to modify ActiveAndroid here's what you could do:
Create some kind of annotation that allows you define a model (Animals) as something that isn't persisted (refer to com.activeandroid.annotation.Table).
Upon trying to executing queries for that class you could use reflection to determine its child classes and then have it perform that query per child class.
Then you would basically take the list of results for each query and combine them into a single list and return that.
To be honest I've never seen inheritance in any Android ORM libraries, and personally I don't think it's a good design pattern for models. You may want to reconsider your reasoning for going down this path.

Java - JPA: How can I create a table for each subclass but not for superclass?

I have a class structure like:
abstract class A {
String a;
}
class B extends A {
String b;
}
class C extends A {
String c;
}
Now I want JPA to create a table for each subclass.
I have looked some previous questions but I am confused. How can I map these classes?
If the A is inherited because of mappings and you do not need separate entity for it, you can defined it as MappedSuperClass. Mapped superclass is only for inheriting mappings, you cannot query it.
On the other hand if real inheritance is needed - depending about implementation - you can go for table per (concrete) class inheritance strategy. Support for this strategy is optional, so it is not guaranteed to work with all implementations. It is supported at least with fresh versions of
Hibernate
DataNucleus
OpenJPA
EclipseLink.
In your case needed step would be then to add following to the class A: #Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
Why not annotate Class A with #MappedSuperClass use Table sub class or Table for Concrete Class inhertience strategy

JPA: Implementing Model Hierarchy - #MappedSuperclass vs. #Inheritance

I am using Play Framework 1.2.4 with PostgreSQL and JPA. I would like to have a Model hierarchy and see that there are some alternatives to doing this.
I have a base class (which is abstract) and two concrete classes extending this base class. I don't want to persist this base class while I want to have concrete classes. In the base class, I have another Model classes as properties, in other words, I have #ManyToOne relationships in my base class.
My question is what is the best way of implementing this? Using #MappedSuperclass or #Inheritance with TABLE_PER_CLASS strategy? I am a bit confused as they seem virtually equivalent.
I also have some concerns about querying and performance issues that I might face in future.
MappedSuperClass must be used to inherit properties, associations, and methods.
Entity inheritance must be used when you have an entity, and several sub-entities.
You can tell if you need one or the other by answering this questions: is there some other entity in the model which could have an association with the base class?
If yes, then the base class is in fact an entity, and you should use entity inheritance. If no, then the base class is in fact a class that contains attributes and methods that are common to several unrelated entities, and you should use a mapped superclass.
For example:
You can have several kinds of messages: SMS messages, email messages, or phone messages. And a person has a list of messages. You can also have a reminder linked to a message, regardless of the kind of message. In this case, Message is clearly an entity, and entity inheritance must be used.
All your domain objects could have a creation date, modification date and ID, and you could thus make them inherit from a base AbstractDomainObject class. But no entity will ever have an association to an AbstractDomainObject. It will always be an association to a more specific entity: Customer, Company, whatever. In this case, it makes sense to use a MappedSuperClass.
#MappedSupperclass is different than the #Inheritance annotation.
#MappedSuperclass tells the JPA provider to include the base class persistent properties as if they were declared by the child class extending the superclass annotated with #MappedSuperclass.
However, the inheritance is only visible in the OOP world, since, from a database perspective, there's no indication of the base class. Only the child class entity will have an associated mapped table.
The #Inheritance annotation is meant to materialize the OOP inheritance model in the database table structure. More, you can query a base class annotated with #Inheritance but you can't do that for a base class annotated with #MappedSuperclass.
Now, the reason why you'd want to use the #Inheritance JPA annotation is to implement behavior-driven patterns like the Strategy Pattern.
On the other hand, #MappedSuperclass is just a way to reuse both basic properties, associations, and even the entity #Id using a common base class. Nevertheless, you can achieve almost the same goal using an #Embeddable type. The only major difference is that you can't reuse an #Id definition with #Embeddable, but you can do it with #MappedSuperclass.

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]

Categories