Setting JoinColumn parameters insertable and updatable to null - java

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.

Related

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).

ManyToOne relation in Hibernate, not in Database

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

Read-only association with JPA OneToMany mapping

I have a transactional entity associated to another entity whereby the associated should not be updated in an case.
Eg. Case *-> User
Where a Case is owned by a User and reversely a User can have many associated Case.
The association is mapped using OneToMany and JoinColumn JPA annotations.
I have also tried marking the Trasactional annotation for User entity as readonly and also made the fetch methods Transient. But this doesnot seem to stop update on User if its state is changed.
Please help me a figure a way to declare a "read-only" association to User.
You can add updatable=falseon #JoinColumn annotation.
Furthermore you should not add a setter method for user in your Case entity and same for caseSet in your User entity. The getter getCaseSet in User entity should also return an unmodifiable collection:
public Set<Case> getCaseSet() {
return Collections.unmodifiableSet(caseSet);
}
The Column annotation and XML element defines insertable and updatable options. These allow for this column, or foreign key field to be omitted from the SQL INSERT or UPDATE statement. These can be used if constraints on the table prevent insert or update operations. They can also be used if multiple attributes map to the same database column, such as with a foreign key field through a ManyToOne and Id or Basic mapping. Setting both insertable and updatable to false, effectively mark the attribute as read-only.
In #OneToMany mapping, #JoinColumn annotation, add both updatable=false and insertable=false, then specify the cascade type as PERSIST instead of ALL
#OneToMany(cascade = CascadeType.PERSIST)
#JoinColumn(name = "<ReadOnlyTableName>", updatable = false, insertable = false)

#Column(s) not allowed on a #ManyToOne property

I have a JPA entity with a property set as
#ManyToOne
#Column(name="LicenseeFK")
private Licensee licensee;
But when I deploy on JBoss 6 the application throws an error saying:
org.hibernate.AnnotationException: #Column(s) not allowed on a #ManyToOne property
I use Hibernate 3.5 as the JPA 2.0 implementation.
What should I use to reference the foreign key column?
Use #JoinColumn instead of #Column:
#ManyToOne
#JoinColumn(name="LicenseeFK")
private Licensee licensee;
#Column
The JPA #Column annotation is for basic entity attributes, like String, Integer, Date.
So, if the entity attribute name differs from the underlying column name, then you need to use the #Column annotation to specify the column name explicitly, like this:
#Column(name="created_on")
private LocalDate createdOn;
#JoinColumn
The #JoinColumn annotation is used to customize a Foreign Key column name, and it can only be used with an entity association.
So, in your case, because you are using a #ManyToOne association, you need to use #JoinColumn:
#ManyToOne(fetch=FetchTYpe.LAZY)
#JoinColumn(name="LicenseeFK")
private Licensee licensee;
Notice that we set the fetch attribute to FetchType.LAZY because, by default, FetchType.EAGER is used, and that's a terrible strategy.
Using #JoinColumn and #Column together will result in the same error.
Change it to only use: #JoinColumn to fix it.
In my case #VaishaliKulkarni's answer was helpful to identify the problem.
I missed to write field for #Column annotion and it effected on next field.
#Column(name = "account_id")
// I forgot to write field here
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
So, I was getting exception at "customer" field.

JPA Cascading Delete: Setting child FK to NULL on a NOT NULL column

I have two tables: t_promo_program and t_promo_program_param.
They are represented by the following JPA entities:
#Entity
#Table(name = "t_promo_program")
public class PromoProgram {
#Id
#Column(name = "promo_program_id")
private Long id;
#OneToMany(cascade = {CascadeType.REMOVE})
#JoinColumn(name = "promo_program_id")
private List<PromoProgramParam> params;
}
#Entity
#Table(name = "t_promo_program_param")
public class PromoProgramParam {
#Id
#Column(name = "promo_program_param_id")
private Long id;
//#NotNull // This is a Hibernate annotation so that my test db gets created with the NOT NULL attribute, I'm not married to this annotation.
#ManyToOne
#JoinColumn(name = "PROMO_PROGRAM_ID", referencedColumnName = "promo_program_id")
private PromoProgram promoProgram;
}
When I delete a PromoProgram, Hibernate hits my database with:
update
T_PROMO_PROGRAM_PARAM
set
promo_program_id=null
where
promo_program_id=?
delete
from
t_promo_program
where
promo_program_id=?
and last_change=?
I'm at a loss for where to start looking for the source of the problem.
Oh crud, it was a missing "mappedBy" field in PromoProgram.
Double-check whether you're maintaining bidirectional association consistency. That is; make sure that all PromoProgramParam entities that link to a PromoProgram as its parent are also contained in said parent's params list. It's a good idea to make sure this happens regardless of which side "initiates" the association if you will; if setPromoProgram is called on a PromoProgramParam, have the setter automatically add itself to the PromoProgram's params list. Vice versa, when calling addPromoProgramParam on a PromoProgram, have it set itself as the param's parent.
I've encountered this problem before as well, and it was due to not maintaining bidirectional consistency. I debugged around into Hibernate and found that it was unable to cascade the delete operation to the children because they weren't in the list. However, they most certainly were present in the database, and caused FK exceptions as Hibernate tried to delete only the parent without first deleting its children (which you've likely also encountered with the #NonNull in place).
FYI, I believe the proper "EJB 3.0"-way of making the PromoProgramParam.promoProgram field (say that a 100 times) non-nullable is to set the optional=false attribute on the #ManyToOne annotation.

Categories