JPA Inheritance - java

Hi I'm new to JPA and I'm having trouble understanding how it handles inheritance.
I have a specific problem I need solved without changing the DB scheme, but if you can't find a solution I would appreciate solution suggestions with a different DB scheme (Hibernate/TopLink solutions welcome).
If I was unclear or you need more information, please tell me so. Thanks in advance!
I have this database:
TABLE Fruit
Id Varchar (10) Primary Key
size Varchar (10)
fruit_type Varchar(10)
TABLE Apple
Id Varchar (10) Primary Key Foreign Key references Fruit.Id
Apple_Property Varchar(10)
So far my entities look like this :
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="fruit_type", discriminatorType=DiscriminatorType.Char)
#DiscriminatorValue(value="fruit")
public class Fruit implements Serializable {
#Id
protected String Id;
protected String size;
}
#Entity
#DiscriminatorValue(value="apple")
//#PrimaryKeyJoinColumn(name="Id" , referencedColumnName="Id")
public class Apple extends Fruit implements Serializable {
private String Apple_Property;
}
Currently I am able to persist Fruit objects without a problem..
Apple objects persist only when their Fruit object hasn't been persisted yet.
If I try to persist an apple object with an already persisted Fruit object :
Fruit fruit1 = new Fruit("1", "Small");
Apple apple1 = new Apple(fruit1, "red");
provider.create(fruit1);
provider.create(apple1);
I will get an error since JPA tries to create a new row on Fruit table with Id="1"
which already exists.
..

When using JPA to persist a child object (i.e provider.create(apple1) in your case) , a record will be inserted to the child table and all of its parent tables. So provider.create(apple1) will insert a record to the Fruit and a record to the Apple table.
In your example , if you only want to persist an apple object ,just call provider.create(apple1) is enough . It will persist the fruit reference inside the apple object too.
BTW , I suggest the Fruit Table 's PK to be a number type , and uses #GeneratedValue to mark the ID field of the Fruit bean. In this way , you can let the database to generate an ID for you and no longer need to set it explicitly in the java code to avoid this "ID already exist error" because of setting an already existing ID in the java code.

I think this is working exactly as designed. When you use joined inheritance and persist an apple object, JPA will automatically insert into both the apple and fruit tables. You don't need to model an additional relation or JoinColumn in your entity classes.

You are trying to use java inheritance concept while creating the db tables, which is somewhat not possible in this case. I could think one different approach for this problem. Have table fruit_type and fruit.
fruit_type(id, typename,desc)
fruit(id, name, type_id, desc) here type_id will be the foreign key.

I have the same issue and so far the only way I found was to query the parent and construct child with parent. Then remove parent and recreate both records.

Related

POJO data with one to many / many to one relationship(JDBC)

For example I have two entities : Enterprise, Department. Enterprise has many departments, department has one enterprise, so there is a column - Enterprise_ID in Department table.
I have a function for saving Department object
void save(Department department);
To add Enterprise_ID in the table I need to have either reference on Enterprise object or enterprise's id.
Which way is more suitable?
However I prefer do not have such information in department object but on this way how can I save Enterprise_ID in the table ? It seems to me Hibernate somehow doing it.
public class Department{
private long id;
private String name;
private DepartmentType type;
private List<Employee> employees;
//getters()/setters()
}
public class Enterprise{
...
private List<Department> departments;
...
}
Department does not have any information about Enterprise in which it exists. So using only department object I can't insert Enterprise_ID(FK) in department table. But hibernate's save method somehow doing it. How can I do it without hibernate using entities above;
I use JDBC.
To do it the same way as hibernate does, you would have a save(Enterprise) method that would persist the enterprise object to the db and also insert/update the foreign key association.
Hibernate supports both nullable and non-nullable foreign key. In the latter case, it will first insert the enterprise, obtaining its primary key value, and then insert the department's along with the correct foreign key value.
You could do the same. But the save(Department) method would only be able to do updates on the department table and not change the association to the enterprise table. To do that, you would have to change the collection in enterprise and save/update that to the db.
Hibernate will only save/update the foreign key if you change something in the Enterprise.departments collection. It's the only way to do it if you don't have the reverse relation.
In your code, you'll have to use the Enterprise object to update the foreign keys in the Department table.
You could create a bidirectional association, by putting a field 'enterprise' in your Department class, but then you need to keep both relations in synch manually...

Java DB: bind multiple instances of a class to one instance of another class

I don't really know how to describe this problem (as you tell by the dodgy title), so here's a full description of the problem.
I have two classes, Teacher and Class.
Each teacher can teach to several classes and each class has several teachers.
In Java, we've mapped it like this:
public class Class {
#ManyToMany(mappedBy = "classes")
private List<Teacher> teachers = new ArrayList<>();
}
We have a superclass, User, and two subclasses, Teacher and Student. These classes inherit from the User superclass. So, in our database we have a table called Users which stores all users as teachers or students.
Now, students can only be in one class, so they can only have one ClassID stored in the database.
But as I said before, teachers can have several classes. So the point is : How am I able to store all the classes that a teacher has in the database?
I see Java created an extra table, called User_Class, which is probably ment to store all the different classes a teacher has and vica versa. Problem is that I can't find any documentation about how to work with this.
Can someone please give me a hand here?
Thanks in advance.
Before trying to solve this by code, I think you need to understand it from the database point of view.
You are trying to build a many-to-many relationship. This sort of relationship is built by splitting it in two one-to-many relationships.
So, if you have two entities (namely Course and Teacher... I avoid using "classes" to prevent confusion), and one Course can have many Teachers and one Teacher can have many Courses, then a way to create the relation (in the database) would be like this:
Table Courses
courseId (PK)
courseName
Table Teachers
teacherId (PK)
teacherName
Table Courses_Teachers
courseId (FK, PK)
teacherId (FK, PK)
(PK stands for "primary key", and FK stands for "foreign key")
Hope this little introduction helps you visualize the way to solve your problem.
That approach is based on a composite primary key.
This link is about that:
how to make a composite primary key (java persistence annotation)

With Hibernate joined-subclasses, is it possible to duplicate columns in super and sub-tables *and* keep them in sync?

So I have an interesting situation. I've inherited a big mess of code where the original developer decided to forego using inheritance in favor of enums and switch statements...it's a perfect example of this anti-pattern Now it's time to refactor, and I've decided the best way to go about it is to pull out a superclass backed by a table with shared columns and then use the joined subclass inheritance strategy. So far so good...
Now the tricky part is that this code has already been deployed to a production system. Accordingly, my refactored code has to be backwards-compatible with the schema/data out there, and I can't start dropping redundant columns off of the subclass tables until one release in the future. Like it or not, I'm going to have duplicated columns between the parent and child tables for one release cycle.
Luckily for me, hibernate doesn't flip out when it sees that there are duplicate columns between parent and child tables. But the bad news is that it doesn't update said duplicated columns in both tables. The column in the parent table gets updated, but the one in the child is left stale.
For backward-compatibility with the current code, I'd like for the column to be updated in both tables. That way, updates to the entities aren't lost if we have to rollback the release and go back to the old schema. While I know that I could take care of this via triggers, I'm looking for a code-only solution because triggers have a nasty habit of flying under the radar.
Is there anyone out there who can tell me a way to convince hibernate to hit both columns?
A very contrived example of my classes is:
#Entity
#Table(name = "superclass")
#Inheritance(strategy = InheritanceType.JOINED)
public class SuperClass {
#Id #Generated
Long id;
boolean duplicate;
}
#Entity
#Table(name = "subclass")
public class SubClass extends SuperClass {
String otherProperty;
}
With the tables to match:
CREATE TABLE superclass (
id INT PRIMARY KEY AUTO_INCREMENT,
duplicate BOOLEAN
);
CREATE TABLE subclass (
id INT NOT NULL,
duplicate BOOLEAN,
otherProperty VARCHAR(255),
FOREIGN KEY (id) REFERENCES superclass(id)
);
When inserting a new SubClass entity, the duplicate column on the subclass table will be NULL.
Thanks a bunch!
How about defining two properties in your code, mapping one to each column, then keeping them in sync in the code? One is the real property, and one is a sort of shadow property. It's not pretty, but it should be confined to the implementation of one class (or one class and its superclass).
When you are able to drop the column, you can remove the shadow property.

How can I manage to create a many-to-many relationship. The generated entity will have extra attributes.

I have 2 entities: Class(of students) and Student. A student can be in many classes(like in college) and a class has many students. The problem is how to ensure that this entity, generated in the middle, has 2 primary keys, the ids of each other entity (Student and Class).
I need to know how to create it using annotations. I use EJB3 and JPA Annotations in the project.
First, you don't need a middle entity. You have two entities and a join table between them.
You need a middle entity only if you have additional information about the relation - for example a StudentClass may have timesAbsent column.
In case you really need the third entity, you can have:
an #EmbeddedId, where you define a separate class holding the two parts of the primary key. That class must be #Embeddable
an #IdClass which will let you specify two #Id fields. You'll again need another class to hold the two fields representing the key.
See this question for which option to choose.
Note that you thus have a composite primary key, not two primary keys (which you can't have)
I know how to make this happen using hibernate. May be it'll help.
Make the collection type Set.
public class CollegeClass {
private Set<Student> students;
}
public class Student {
private Set<CollegeClass> classes;
}

JPA to retrieve name-value from child table without using model for child

This is something I'd really like to be able to do - resolve names based on id values without fetching the whole child model.
Here is an example of what I have, a Table say Employee and a Name_Details table
The Employee may look like this
Create Table Employee {
emp_idinteger not null generated by default as identity; -- generated pk
Department varchar(44);
emp_name_id Integer; -- fk to Name_Details table
...other details such as hire_date etc..
}
now emp_id is a foreign key to the name_details table which may look like this:-
Create Table Name_Details {
id Integer;
Name varchar(32);
Address Varchar(127);
Postcode Varchar(10);
--other details..
}
My question is that I'd like to model the first table Employee with a Java class but I am not interested in setting up a one-to-one relationship between the Employee class and the Name_Details table to fetch that whole Name_details table (as its quite large) the only information I want from this second class is just the Name field (found by joining the emp_name_id column with the Name_Details.id column.
So is it possible in JPA to say declare something like a transient variable in my Employee class called say String employeeName and have this retrieved by JPA based on the above relationShip?
This is a simplified example of what I have wgere there are several tables with name-value pairs and the master table has the values. I need this for reading and not updating/deleting etc.
I am not using JPA v1.x with EJB3 (and not hibernate) on WPS 6.1
Thx G
There are a few options.
The first is to just create a Name class that maps to Name_Details but only maps the name and id fields. Employee would then have a OneToOne to Name, and only the name would be read.
A second option is define Name_Details as a #SecondaryTable in Employee and map only the name from it. The JPA spec restricts the secondary table join to have to share the same id, but depending on what JPA provider you are using, using the 1-1 foreign key may be possible (EclipseLink does support this). You could also define a view the does the join and map to the view.
A third solution is to still map all of the Name_Details fields but define them as LAZY. If your JPA provider supports LAZY basics (or fetch groups), then these will not be fetch unless accessed.

Categories