ManyToOne relation in Hibernate, not in Database - java

I have an entity named 'Department' and another entity named 'student'. I know the department will have many students and there shoulld be relation between these two tables in database. But in my project, the DB tables are already there and there is no relation (foreign key) between department and student tables.
In entity class, student.java , there is a relation written as,
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = 'DeptId', nullable = false, insertable = false, updatable = false)
Department department
I am confused about this existing code.
When I wrote a test, I am fetching the department from DB by deptId and set the student entity as,
student.setDepartment(department);
This doesn't populate the DB column 'DEPTID' in student table.
Since there's no student collection in Department, I cannot set the student as,
department.addStudents(student);
I am not sure whether we can insist a #ManyToOne relation without a relation between the tables in DB.
Please let me know how I can fix this issue so that the 'DEPTID' column in student table is populated with the correct data.
Thanks in advance,
BS

you r having
#JoinColumn(name = 'DeptId', nullable = false, insertable = false, updatable = false)
instead why dont you try
#JoinColumn(name = 'DeptId', nullable = false)
Hibernate wont check whether the mapping constraints that you are putting are valid at db level. It just assumes it is valid and executes queries based on that assumption.

Hi sorry for responding to your question so late but I think the reply could equally help another person. Now you said the tables existed already in the database, if they haven't yet got some data then I suggest you drop them, activate your Table Generation Strategy in your persistence.xml file to Create, in that case, it will recreate those tables with your desired relationship columns. Do not also forget to use the #OneToMany annotation on the Department.java class to indicate its capabilities of reception of many students. It is used together with the #ManyToOne

Related

Bi-directional #OneToOne mapping creating records using hibernate

When saving a bi-directional #OneToOne mapping, is hibernate supposed to make a record on both tables?
I have a table interview with column applicant_id that references applicant table with field interview_id and vice versa, the columns being the FKs.
When creating a column by executing session.save(theInterview) is hibernate supposed to create a record in applicant table applicant_id? Do I need to update the existing record myself or am I doing things wrong?
Edit
Just was working on my JSP file and noticed that I could see that the reference exists on the applicant too. But the query on the DB shows the field empty?
Hibernate Mapping
#OneToOne(mappedBy="applicant_id", cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "interview_id")
private Interview interview_id;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "applicant_id", nullable=false)
private Applicant applicant_id;
Interview_id column on an applicant after recording an interview instance.
Can you provide your Hibernate mapping? What your asking about is Cascade, i.e. should Hibernate cascade save of the Applicant. That depends entirely on whether Hibernate has been instructed to cascade save on the relationship.

How to replace a #JoinColumn with a hardcoded value?

For more context, please see my other question.
I want to join my Employee entity class to Code entity class but the Code PK is composite (DOMAIN, CODE) because it lists many different code domains, yet the codes that go in the Employee class/table are all from within a single domain, eliminating the need to have a domain field in the Employee class/table (because it would always be the same).
Can I join Employee to Code by using the CODE field in the Employee table and a hardcoded value (e.g. EMP_TYPE) instead of a redundant column?
If my Employee class/table did indeed have that redundant column, I would join it like this:
#JoinColumns({
#JoinColumn(name = "EMP_TYPE_CODE", referencedColumnName = "CODE"),
#JoinColumn(name = "DOMAIN", referencedColumnName = "DOMAIN)})
#ManyToOne(optional = false)
private Code sharedStatute;
but I REALLY don't want to have that extra column in the DB and in the class because it will always be the same.
What I am trying to accomplish would be equivalent to the following in SQL:
SELECT e.emp_id, e.first_name, e.last_name, c.description as emp_type
FROM Employee e JOIN Code c
ON e.emp_type_code = c.code
WHERE c.domain = 'EMP_TYPE'
as opposed to adding a field domain in the Employee table and populating EVERY SINGLE RECORD with the same value ('EMP_TYPE') and then doing:
SELECT e.emp_id, e.first_name, e.last_name, c.description as emp_type
FROM Employee e JOIN Code c
ON e.emp_type_code = c.code
AND e.domain = c.domain
The former is more efficient because it saves me from having to have a redundant field. So what I am trying to do is the same thing but in JPA.
Some of you may say something to the effect of "why not have a separate lookup table for each code" but I think that's a terrible idea and causes cluttering of DB tables and corresponding application entities. It is much better to have a single code lookup table partitioned by code type (or domain).
This should work?
#JoinColumn(name = "EMP_TYPE_CODE", referencedColumnName = "CODE")
#Where(clause = "domain = 'EMP_TYPE'")
#ManyToOne(optional = false)
private Code sharedStatute;
Note: Apparantly this solution is OpenJPA only.
There is a way to do this with javax.persistence annotations only:
#JoinColumns({
#JoinColumn(name = "EMP_TYPE_CODE", referencedColumnName = "CODE"),
#JoinColumn(name = "CODE_TABLE_NAME.DOMAIN", referencedColumnName = "'EMP_TYPE'")})
#ManyToOne(optional = false)
private Code sharedStatute;
Note the single quotes in the referencedColumnName, this is the String value you are looking for.
There is a downside however, when you have multiple Code objects in your entity, the join on DOMAIN will be done only once in jpa, giving bad results. At the moment I circumvent this by making those field load lazily, but that's not ideal.
More information here.

JPA Read but not write/update an attribute

I have a JPA Entity that has an attribute declared in the following way
#OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinColumn(name = "userId", referencedColumnName = "id", insertable = false, updatable = false)
private UserBare user;
(UserBare is a dummy entity I've created which is a dumbed down version of a User obj as I needed some date, not all of User obj be made available to this entity. Is there a better way to approach this?
This is a convenience attr that I use just make the userBare object available to this entity when reading this entity. But when I actually write this entity, it seems to create new entries of 'user' in the database (instead of updating). I already have insertable=false,updatable=false but it still writes to the database. I tried removing the CascadeType declaration but that is throwing an error.
Here is the database snapshot after the unwanted rows are added (last 3). Also I've noticed that deleting the original entity did not delete these three unwanted rows. So I guess JPA is storing them but the references are intact to the original entity.
My souspicioun would be that "OneToOne" means "OneToOne" excluding the possibility of "OneToZero" if you don't set Optional to true like this:
#OneToOne(optional=true)
But just a guess.. I'm not sure

How can I access the underlying column after defining a #ManyToOne relationship on it in Spring?

I'm using Spring 3.2 with Roo 1.2.3 to build a database-backed Java application via Hibernate. I have several bidirectional OneToMany/ManyToOne relationships among the tables in my database. When I set up the ManyToOne side of the relationship using #JoinColumn (via "field reference" in Roo), a new field whose type is the related entity (the "one" in ManyToOne) is created. However, once this is done, there seems to be no way to access the underlying column value on which the ManyToOne relationship is based. This is a problem when the underlying join column contains data needed by the application (i.e. when the join column contains product stock numbers).
Is there any way to set up my entity class so that the column on which its ManyToOne relationship is based remains accessible without traversing the new join property? How can I define an accessor method for the value of this column?
I've been looking online for an answer to this question for several days, but to no avail. Thanks in advance for your help.
just map the column a second time with insertable=false and updateable=false
To make it more concrete. It's possible to do a HQL-SELCT and restrict a ManyToOne relationship, without any join in the resulting SQL:
Instead of using a join in
session.createQuery("FROM Person person WHERE person.adress.id = 42")
we use can use the adress_idcolumn
session.createQuery("FROM Person person WHERE person.adressId = 42")
This works, if you specify an additional adressId field, which is only used as mapping info for Hibernate:
#Entity
#Access(AccessType.FIELD)
public class Person{
#Id
String id;
#JoinColumn(name = "adress_id")
#ManyToOne(fetch = FetchType.LAZY)
#Nullable
public Adress adress;
#Column(name = "adress_id", insertable = false, updatable = false)
private String adressId;
}
#Entity
#Access(FIELD)
public class Adress{
#Id
String id;
}
The AccessType.FIELD is not needed (But we can leave getters/setters in example). The FetchType.LAZY and #Nullable are also optional, but make it clear when it makes sense to use it. We are able to load Person entities which have a specific Address (we know the address id). But we don't need a join because it's not needed for the WHERE-clause and not for the initial fetch (the address can be fetched lazy).

Setting JoinColumn parameters insertable and updatable to null

I have seen a couple of examples on the Internet about using JoinColumn like the way in the example below.
Actually, there are two questions I want to ask you about this partcular example. Can't we just get rid of the "optional" parameter by adding a "nullable=false" parameter to the JoinColumn. Are there any differences between optional and nullable entity relationship-wise?. What are the advantages of setting insertable and updatable to false in the joincolumn? Is this done to ensure that Employee entity cannot update the Department entity?
#Entity
public class Employee {
// ...
#ManyToOne(optional=false)
#JoinColumn(name="DEPT_ID", insertable=false, updatable=false)
private Department department;
// ...
}
optional = false on the ManyToOne is a runtime instruction for the persistence framework to interpret when building java objects. nullable = true on the JoinColumn is for setting up the database schema and may or may not be interpreted at runtime depending on your persistence provider.
Normally that JoinColumn mapping is done that way to indicate that the relationship is managed from the other side, by the Department.
You would likely have:
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="DEPT_ID")
private Set<Employee> employees;
Over on your department, and you'd create new employee-department relationships by adding them to the collection there, rather than setting a Department on the Employee. That's why you mark the Employee's department as non-updatable, because the Department "owns" the ability to modify the relationship.

Categories