Inheritance on Hibernate objects without table mapping - java

I want to use hibernate objects in project as defined below.
#Table(name = "Parent")
class Parent{
int id;
String name;
}
#Table(name = "Child")
class Child extends Parent{
String schoolNo;
}
But in the database;
There is no relation with these two table.
Parent tables columns are; id, name
Child tables columns are; id, name and schoolNo
If I use
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
when I send a query for Parent object, hibernate use UNION on Child and Parent tables but I want to select from only Parent table.
And if I use
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
hibernate wants a discriminator column.
I need hibernate sends select query for each class to its table.
Best regards.

TABLE_PER_CLASS is the correct strategy here.
It's odd that Hibernate generates a union query over both tables, but that should still work. The subquery over the wrong table won't find anything, so the results will be correct. This sounds like a bug in Hibernate's query generation for subclasses.

In a similar situation, I use #Inheritance(strategy = InheritanceType.JOINED) on the parent table.
See more info in the Hibernate docs: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#d0e1168

Related

Creating missing subclass entity when super exists

I have 2 tables S and I on the database (with a 1:1 relationship), they both have the same id as pk and the hibernate classes I've created are like these:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class S {
#Id
#Column(name = "id")
#GeneratedValue(...)
#SequenceGenerator...
private long id;
....
}
#Entity
#PrimaryKeyJoinColumn(name = "id")
public class I extends S {
....
}
Because of historical reasons, in the database there are objects of type S but not the associated objects of type I. I want to create those I type objects using hibernate. How can I do that? Can I create an I type object from an left join HQL query like this?
select i from I i right join i.id s where s.id = :id
If I try to create a new I entity (new I()) and then persist it, I only managed to get some exceptions as it tries to create an already existing S record. I can't do a simple read/load for I entity as I record does not exist yet. How can I do to create this missing I part entity?
PS I will adjust the question if you point me the unclear things
One approach that will certainly work for you (while is isn't clean one) is to create I records with SQL inserts directly: insert into I_table values (...).
When there are corresponding records in I_table, ORM will start load your objects with I type.
If you have to stay with your ORM and you can delete S records then you can
Load S by id
Delete S (flush? based on your flush mode)
Create I
Copy S values into I
Save I
What you're trying to create is an entity hierarchy. So have to map the entities correctly. The following is probably what you need:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(discriminatorType = DiscriminatorType.CHAR)
#DiscriminatorValue("S")
public class S {
#Id
//........
private long id;
....
}
#Entity
#DiscriminatorValue("I")
public class I extends S {
....
}
With this setting the table S will contain a column named DTYPE (for discriminator type) which identifies whether a row belongs to S or I; this is the default; if you don't want that you have to give a name for the DiscriminatorColumn annotation.
Create an instance of S and save
Create an instance of 'I' by populating the inherited properties (i.e., the properties of S) and its own properties, and save.
When you create a query targeting I, you'll get only instances of I, but if your query targets the S, you'll get instances of both entities.

Hibernate upgrade object from parent class to child class in JOINED inheritance

I'm using Spring Data Jpa and Hibernate on my project.
I have three tables:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
class Parent {
String id;
String name;
}
#Entity
class FirstChild extends Parent {
...
}
#Entity
class SecondChild extends Parent {
...
}
On the first step of my logic I should save Parent object without child type.
And on the second step I know to which Child table it should belong.
For example:
Parent parent = parentRepository.findById("id");
FirstChild firstChild = new FirstChild();
firstChild.setId(parent.getId());
firstChild.setName(parent.getName());
parentRepository.save(firstChild);
But when I do a Hibernate save it throws me exception:
o.h.e.i.DefaultLoadEventListener Load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null
As I understand it doesn't know how to upgrade entity from parent to child type and just throws an exception because of conflict - entity with same id is already there.
Is there any solutions for this problem?
JPA is a means of mapping your Java domain model onto a relational database schema. Since there is no such thing as 'promoting a parent class to a child class' in Java, there is no support in JPA for such an operation.
That being said, you could probably achieve the desired behavior using a native update query. You would need to update the discriminator column (DTYPE) column, and insert a new row into the table corresponding to the child entity (note that in the SINGLE_TABLE strategy, updating the discriminator column would suffice).
A much better solution IMHO, is to delete the parent entity and insert a new child entity. If you're concerned about referential integrity, perhaps you should switch from inheritance to composition.

Constrains on class name for hibernate query in java

Sorry if it is a stupid question but I don't know Java almost at all.
I have a table "Orders" in a postgreSQL database, which I access by Hibernate, mapping the table to a class:
#Entity
#Table(name = "Orders")
public class Orders { ... }
This works. However, if I change the class name to "Order", thus:
#Entity
#Table(name = "Orders")
public class Order { ... }
I get an error:
org.hibernate.hql.ast.QuerySyntaxException: Orders is not mapped [from Orders]
of course I have already updated the hibernate xml config file, switching from
<mapping class="<path>.orders.Orders"/>
to
<mapping class="<path>.orders.Order"/>
any idea why ? What am I missing ? The mapping between the DB table and the class is established only on the basis of the #table annotation and not on the class name, isn't it ?
You're missing the fact that JPQL is not SQL. It works on entity names and property/field names, not on table names and column names. Since you changes the name of the entity class from Orders to Order, you need to change your JPQL queries from
select o from Orders o ...
to
select o from Order o ...
The name of the table that the entity maps is completely irrelevant.

JPA - how to model this join with conditions?

I was trying to find an answer but, unfortunately, with no luck.
The data structure looks like this:
TABLE_X - contains userId, also userType telling if this is external or internal user
INTERNAL_USERS - contains key userId
EXTERNAL_USERS - also contains key userId
TABLE_X.userId is either INTERNAL_USERS.userId or EXTERNAL_USERS.userId.
Now, I would like to map an entity out of TABLE_X and have user object mapped to correct entity, either INTERNAL_USERS or EXTERNAL_USERS.
How should I do this?
Should I create two fields and map one to INTERNAL_USERS and one two EXTERNAL_USERS and just see which one is not empty?
If I understand correctly your question, what you have to do is to replicate structure of the TABLE_X columns with fields on the TABLE_X class, and add to fields one for INTERNAL_USERS.userID and one for EXTERNAL_USERS.userID
But if you store on TABLE_X.userType if a user is internal or external, I think that the best thing you can do is not create any other table, because you just have the information you need on your first table (TABLE_X). If you want to know all the users that are internal for instance, just do a SQL and select all the values from TABLE_X where userType = "Internal"
Use Hibernate inheritance. Check out the Table per class inheritance pattern. Here you have both INTERNAL_USERS or EXTERNAL_USERS data in TABLE_X with userType as the discriminator column.
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1191
Given the table structure, you can use JPA Inheritance as detailed here:
https://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Example_joined_inheritance_annotations
In Hibernate you can model such relationships as follows. When querying for a User you can then rely on Hibernate to return an instance of the correct type.
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public class User{
#Id
private Long userId;
}
#Entity
public class InternalUser extends User{
}
#Entity
public class ExternalUser extends User{
}
As noted in the article linked to, Hibernate does not require a discriminator column to be specified when using joined inheritance. It does however support a discriminator column if one is available. As you have one available in your schema - userType - then you could explicitly specify it if you wish. I imagine this would yield some performance benefit in terms of the generated SQL:
Mappings with optional discriminator column:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="userType")
public class User{
#Id
private Long userId;
}
#Entity
#DiscriminatorValue("INT")
public class InternalUser extends User{
}
#Entity
#DiscriminatorValue("EXT")
public class ExternalUser extends User{
}

JPA Inheritance demanding ID in subclass

I'm working on a project with Struts2 along with JPA with Hibernate.
I have two entities User (id,email) and Customer (user_id).
Since it's natural to think that every Customer is a User I had the Customer Inherit from the user. Here's the relevant code of the entities:
User:
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.JOINED)
public class User implements Serializable {
#Id
#GeneratedValue
private int id;
private String email;
...getters and setters...
}
Customer
#PrimaryKeyJoinColumn(name = "user_id",referencedColumnName = "id")
#NamedQueries({
#NamedQuery(name = "Customer.getByCustomerUserId", query = "SELECT C FROM Customer C where C.id=:id")
})
public class Customer extends User implements Serializable {
}
If I run the query Customer.getByCustomerUserId I keep getting the error:
Unknown column 'customer0_.id' in 'where clause'
I tried following the answer given here by creating a BaseEntity having the Id field and having the User Entity inherit from it but there's no effect. I still keep getting this error message. Can someone Please tell me what's going wrong?
I suspect that there is no reference in the customer table to the user table, or there is something similar off with the constraints.
I suggest that you rename your entity classes and let Hibernate generate tables from them. Then use your query on the new entities, and if you have no problems, you should inspect the differences between the new tables and the existing ones (use 'Create table script' option in some DB tool).
Drop primaryKeyJoinColumn statement.
Then insert #ForeignKey(name="CHOOSE_A_NAME").
Generate your ddl and run it (with the constraints)
By default, inheritance mecanisms will use the Pk defined in superClass ( whatever his name)
ENjoy

Categories

Resources