multiple discriminator columns for persistent subclasses - java

I have banged my self with a very particular problem. Using OpenJPA (KODO 4.1) is there a way to use more than one column as a discriminator column?
My problem is that i have a table structure (which i have limited ability to modify of course) similar to this:
Table VEHICLE EXPENSIVE_CAR CHEAP_CAR EXPENSIVE_BOAT CHEAP_BOAT
---------------------------------------------------------------------------------
HORSE_POWER LUXURY_ACC CLASIFICATION SIZE SIZE
MEDIUM EXTRAS TV_SIZE
IS_EXPENSIVE CLASIFICATION
Where medium would discriminate between boat and car and is expensive would discriminate bettwen expensive or cheap.
So, is there any way to achieve this with the inheritance capabilities provided by OpenJPA (i know hibernate can use discriminator formulas but i am trying not to switch from the default JPA provider).
As a bonus if you can tell me about the custom discriminator strategies from OpenJPA that would be great since i have a hunch that it could be a plausible solution (even though i would prefer a vendor independent one)
Thanks a lot

Let's start backwards.
Discriminator strategies define the type of the column that discriminates related entities in the hierarchy. In JPA 1.x, it can be either a string (this is the default), a char and an integer.
Example:
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
#Entity
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING, length = 5)
#DiscriminatorValue("FOO")
public class Foo { ... }
#Entity
#DiscriminatorValue("BAR")
public class Bar extends Foo { ... }
#Entity
#DiscriminatorValue("BAZ")
public class Baz extends Baz { ... }
If you are using is single table inheritance strategy as the default, this setup means that all these entities that are in the hierarchy will be mapped to the database table of the parent class, meaning you'll have a FOO table in your db with all the attributes of classes Foo, Bar and Baz plus a discriminator column called TYPE with the type of string (most likely some varchar-variant, length 5) and for each entity type, the respective discriminator value will be inserted automatically when persisted.
When you are finding Bar or Baz entities with JPQL, JPA will be able to find the entities from the FOO table (because that is the parent entity's table), and by relying on the contents of the discriminator column, your JPA provider will be able to discriminate between creating some Bar or Baz entities.
If you'd set the discriminator type to INTEGER or CHAR, then you could write for the values 1, 2, 3 or "A", "B", "C" etc. respectively.
Now to the OpenJPA question.
AFAIK there's no way to easily specify multiple discriminator values with OpenJPA, but you can create some more complex entity hierarchies, so if you'd be able to modify the schema, you could create a Vehicle entity, a Car, a Boat and both an ExpensiveBoat and an ExpensiveCar.
If you have to stick with your schema, I guess (but FIXME) you are using the joined or the table per class inheritance strategy which means you cannot use the discriminator feature that JPA provides.

Related

Getting around "Table per Concrete Class" in Hibernate inheritance mapping strategy

In my java I have a generic class (could be abstract or non-abstract either way, but does NOT map to a table in the database). It has one or more variables that are common to every class. Example:
public class GenericThing {
private Date createDate;
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date dt) {
createDate = dt;
}
}
This is useful because literally every table in the database has the column CREATE_DATE.
In this case the right inheritance strategy to use in Hibernate is "table per concrete class". But, this is "bad", they say, because each table requires that identical column and if you change that column name (CREATE_DATE) you have to change every table's column name. Well, obviously this is true, but what is the alternative? Obviously I do want every table in the database to store the Create Date, but I don't want every object in the entire database to be in one table, so that precludes (as far as I know) all the other mapping strategies, right?
Actually for your usecase, nothing wrong in using Table per concrete class strategy
The problem you are trying to solve is not creating any redundancy at schema level(when tables are created). Even if we do the entity modelling in reverse mode, this is fine. In-fact, create_date is specific to each row for every table.
Table per concrete class is not recommended only when you are dealing normal inheritance for example User -> Customer -> Supplier where each extended class is a kind of parent class and the specific extra attributes added in the sub class need not be duplicated in the all the tables (Join Table strategy is recommended for such cases)
What's wrong with table pet subclass polymorphism? The parent table contains the commom columns, child tables the specifics.

Why do we use #Embeddable In Hibernate

What's the use of #Embedded and #Embeddable In Hibernate ? Because every example i found on internet is inserting data inside of a single table and to do that using two different class. My point is if I am using a single table then I can map all the columns inside of a single class then why should i use different class. and if We use two different table then there is one-to-one and one-to-many hibernate relationship.
There are two types of objects in Hibernate
1. Value Object
2. Entities
Value Objects are the objects which can not stand alone. Take Address, for example. If you say address, people will ask whose address is this. So it can not stand alone.
Entity Objects are those who can stand alone like College and Student.
So in case of value objects preferred way is to Embed them into an entity object.
To answer why we are creating two different classes: first of all, it's a OOPS concept that you should have loose coupling and high cohesion among classes. That means you should create classes for specialized purpose only. For example, your Student class should only have the info related to Student.
Second point is that by creating different classes you promote re-usability.
When we define the value object for the entity class we use #Embeddable.
When we use value type object in entity class we use #Embedded
suppose we have employee table annotated with #entity and employee has Address so here i dont want to create two tables i.e employee and address, i just want create only one table i.e employee not Address table then we need to declare Address instance in Employee and add #embedable annotation on top of Address class, so finally we get table employee with its record and address records as well in single employee table
One entity can be embedded in another entity. The attributes of an entity can be common attributes of more than one entity. In this case there can be one embeddable entity. And this embeddable entity can be embedded in more than one entity.
Let's consider an example. We have one Animal entity, which has name and location attributes. Now two different entities Lion and Elephant can have Animal attributes just by embedding the Animal entity. We can override the attributes. In Animal entity there is location attribute and in Elephant there is place attribute. So with the help of #AttributeOverrides we can do like below:
#AttributeOverrides({ #AttributeOverride(name = "location", column = #Column(name = "place")) })

Hibernate : Difference between # Embedded annotation technique and #OneToOne annotation Technique

What is the difference between #Embedded annotation technique and #OneToOne annotation technique because in Embedded the java class contain "Has a" relationship in class and with the help of #Embedded annotation we persist the has a object in database. and in OneToOne relationship we also persist the has a object in database.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. For example a Customer might always have one record in a Name table.
Alternatively if those name fields are on the Customer table (not in a separate table) then you might want an #embedded. On the face of it you could just add the name fields as standard attributes to the Customer entity but it can be useful if those same columns appear on multiple tables (for example you might have the name columns on a Supplier table).
Its the difference between composition and aggregation. #Embedded objects are always managed within the lifecycle of their parents. If the parent is updated or deleted, they are updated or deleted as well. #OneToOne objects may mimic composition via the cascadeType option of their #Join annotation, but by default they are aggregated, aka their lifecycle is separate from that of their parent objects.
#Embedded is used with Value Objects (Objects which have a meaning only when attached to an Object) whereas one to one mapping is between two objects having their own existence and meaning.
For e.g.
Value Object and #Embedded: If we have a User class and this class has an address Object in it, it can be considered as a value object as the address alone does not have any significance until unless associated with a user. Here address object can be annotated with #Embedded.
One to One mapping and #OneToOne: If we have a User class and this class has a 'Father' Object or a 'Mother' object, we would want to annotate the 'Father' or 'Mother' instance as #OneToOne as 'Father' or 'Mother' have their own meaning and existence and are not Value objects to User class.
A closely related difference is between #OneToMany and #ElementCollection. Both are used to save instance variables of Collection type in Java class. The difference being, #ElementCollection is to be used when the elements of Collection being saved are Value Objects whereas #OneToMany is used when the elments and object have well defined meaning and existence.
Use #OneToOne, only if fields can be reused. Otherwise, go for #Embeddable.
A quote from Beginning Hibernte, 3rd Edition:
There is nothing intrinsically wrong with mapping a one-to-one association between two entities where one is not
a component of (i.e., embedded into) the other. The relationship is often somewhat suspect, however. You should
give some thought to using the embedded technique described previously before using the #OneToOne annotation.
#Embeddable:
If the fields in an entity (X) are contained within the same table as another entity (Y), then entity X is called "component" in hibernate terms or "embedded" in JPA terms. In any case, JPA or hibernate do not allow to use 2nd table to store such embedded entities.
Generally, we think of normalizing a table when data is being reused by more than one table. Example: A Customer (id, name, street, city, pin, landmark) can be normalized into Customer(id, name) and CustomerAddress(cust_id, street, city, pin, landmark). In this case, we can reuse CustomerAddress by linking the same using cust_id with other tables. But if this reuse is not required in your application, then we can just keep all columns in one table.
So, a thumb rule is,
If reuse -> #OneToOne,
If no reuse -> #Embeddable
#Embedded is typically to represent a composite primary key as an embeddable class:
#Entity
public class Project {
#EmbeddedId ProjectId id;
:
}
#Embeddable
Class ProjectId {
int departmentId;
long projectId;
}
The primary key fields are defined in an embeddable class. The entity contains a single primary key field that is annotated with #EmbeddedId and contains an instance of that embeddable class. When using this form a separate ID class is not defined because the embeddable class itself can represent complete primary key values.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. #Id will be the primary key.

How do I extend a hibernate annotated class to point a field to a different hibernate entity?

Let's say I have the following class structure:
/** Boring bits snipped */
#Entity
#Table(name = "Foo")
public class Foo {
#JoinColumn(name = "id")
private Bar bar;
/** Other flat data goes here */
}
#Entity
#Table(name = "Bar")
public class Bar {
/** Some data goes here */
}
For reasons I'm not going to go into, I have copies of these tables which I want to also map too, which should appear in Java to also be Foo and Bar objects. Most importantly, the relationships between tables should be between the copied tables when dealing with copied objects.
What is the most correct way of doing this?
I'm guessing I can probably do something like this:
#Entity
#Table(name = "OtherFoo")
public class OtherFoo extends Foo {
#JoinColumn(name = "id")
private OtherBar bar;
}
#Entity
#Table(name = "OtherBar")
public class OtherBar extends Bar {
}
But is that the right way to do it?
You're close, but you can't just inherit from another entity and change the table like that. Entity inheritance has to follow one of the provided inheritance models. It may be for your use case as simple as adding #Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) to the superclass. There are some limitations to this if you have some more complicated mappings with other classes. Since it won't be able to tell which table a superclass based mapping is actually in, it can't join through it. And mappings to the superclass will require checking both tables every time. You also of course need unique ID generation across all the tables in the hierarchy. You may want to consider using an abstract superclass and having both concrete entities be leaf classes. Then at least you can always work with just a single table when you know which one it is.
Alternately you can declare your column mappings in an #MappedSuperclass and each subclass can then be an entity with a table mapping. That might work better if it's legacy data and you don't have unique IDs across the 'regular' and 'copy' tables.

Is nesting of different types of inheritance allowed in hibernate.?

I have a situation like this...
I have four different tables namely btech_ece, btech_cse, btech_it, btech_eee all these tables have the same columns. Its just that the name differs and everything else is same. Their columns are:
Id
Year
Semister
Section
Period
SubjectCode
Date
Status
now i have four different tables under each division ece, cse, it and eee. btech_cse_1, bteh_cse_2, btech_cse_3, btech_cse_4, btech_ece_1, btech_ece_2 and so on..
the columns of these tables are like this:
Roll_Number
Id
Present
the id column above is a foreign key from the tables btech_cse. My idea was that if i can use a nesting of hibernate's inheritance hierarchy. I could have a class named btech and all the classes btech_cse, btech_ece, btech_eee, btech_it can be its union-subclasses and i can have another class that says btech_cse_num which is a joined subclass of the above union subclass and each class of the form btech_cse_1 could be again a union-subclass of the btech_cse_num class. Is such nesting allowed in hibernate?
How do i best exploit the hibernate's inheritance feature to suit my situation.?
If feasibility is the only concern, then I suggest you look at the hibernate reference documentation. The chapter on "Inheritance Mapping" gives some useful pointers, this is from version 3.3 docs:
Hibernate does not support mixing subclass, joined-subclass and union-subclass mappings under the same root class element. It is possible to mix together the table per hierarchy and table per subclass strategies under the the same class element, by combining the subclass and join elements. It is possible to define subclass, union-subclass, and joined-subclass mappings in separate mapping documents directly beneath hibernate-mapping. This allows you to extend a class hierarchy by adding a new mapping file.

Categories

Resources