#ManyToOne
#JoinColumn(name = "someValue" , referencedColumnName = "someOtherValue" )
What values are to be placed in name and referencedColumnName column if 2 tables are linked by ManyToOne association?
Suppose you have Two tables:
1. Department table with columns:
a. Dept_ID (primary key)
b. Dept_Name
2. Employee Table with following column:
a. Emp_Id (primary key)
b. Dept_Id_fk (foreign key)
c. Salary
Now your join column for Employee Entity class will be
#ManyToOne
#JoinColumn(name = "Dept_Id_fk", referencedColumnName = "Dept_ID")
Department department;
So referencedColumnName means column that you are referencing to from your foreign key column.
How would the join column look like for oneToMany association? Here is an example:
Person table:
person_id (pk), person_name
person_reltn table:
person_reltn_id (pk),
child_person_id (fk),
parent_person_id (fk)
For the above tables, if I were to create the Person entity:
class Person(){
#Id
#Column(name = "PERSON_ID")
private long personId;
#NotFound(action = NotFoundAction.IGNORE)
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(
name = "CHILD_PERSON_ID",
referencedColumnName = "PERSON_ID",
updatable = false,
insertable = false)
#Where(clause = "ACTIVE_IND = 1")
#Filter(
name = FilterConstants.END_EFFECTIVE_DATE_TIME_FILTER,
condition = FilterConstants.END_EFFECTIVE_DATE_TIME_CONDITION)
#Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
private final List<PersonRelation> personRelations = new ArrayList<>();
}
In the joinColumn, should the name always have the foreign key (which means the value from entity you are joining to) and the referenceColumnName should alway have the primary key on the entity? If yes, it will be the opposite of Sayantan's response above. Please let me know if I misunderstood the concept.
Update on 03/04/2021
After doing more research, I found the documentation on how to set the referenceColumnName based on the entity mappings[1]. Looks like, for unidirectional OneToMany mapping, the referenced column is in the table of the source entity.
1.https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html
Related
I am trying to persist a OneToMany parent child relation with Join table, but in insert sql for join table only one column is considered (out of two).
insert into ITEM_BIDS_REL (BID_ID) values (?)
It does not include ITEM_ID column and due to that getting below error.
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("BIDDING_SYSTEM_OWNER"."ITEM_BIDS_REL"."ITEM_ID")
Two question here:
Why it only includes BID_ID column in INSERT query for ITEM_BIDS_REL join table.
Is the right way to design JOIN TABLE like I have kept BID_ID ad PK,FK and ITEM_ID as FK.
Use case:
Referring the "Online Action (bidding) System" example from Java Persistence with Hibernate book.
An Item can have many Bids on it.
ITEM table
ITEM_ID PK
NAME
INITIAL_AMOUNT
ITEM_BIDS table
BID_ID PK
AMOUNT
ITEM_BIDS_REL Join Table
BID_ID PK (FK from ITEM_BIDS table)
ITEM_ID NOT NULL (FK from ITEM table)
Entity classes:
Item Class
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable( name = "ITEM_BIDS_REL",
joinColumns = #JoinColumn(name = "ITEM_ID"),
inverseJoinColumns = #JoinColumn(name = "BID_ID"))
#JsonIgnore
private Set<Bid> bids;
Bid class
#ManyToOne(cascade = CascadeType.ALL)
#JoinTable(name = "ITEM_BIDS_REL",
joinColumns = {#JoinColumn(name = "BID_ID", insertable = false,
updatable = false)},
inverseJoinColumns = {#JoinColumn(name="ITEM_ID", insertable = false,
updatable = false)})
private Item item;
Persistence logic:
public Item addBid(BidDTO bidDTO) {
Item item = itemsRepository.findOne(bidDTO.getItemId());
Bid bid = Bid.builder()
.item(item)
.bidAmount(bidDTO.getBidAmount())
.build();
if(item.getBids() == null){
item.setBids(new HashSet<>());
}
item.getBids().add(bid);
bidRepository.save(bid);
itemsRepository.save(item);
return item;
}
I have a relation between Accommodation and Booking classes, and also I set a foreign key in booking table.
ALTER TABLE `project`.`booking`
ADD INDEX `fk_accId_fk_idx` (`accommodation` ASC);
ALTER TABLE `project`.`booking`
ADD CONSTRAINT `fk_accId_fk`
FOREIGN KEY (`accommodation`)
REFERENCES `project`.`accommodation` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
Accommodation class:
#Entity
....
public class Accommodation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private BigInteger id;
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
......getters setters
}
Booking class:
#Entity
public class Booking implements Serializable {
......
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "bookings", nullable = true)
#JsonBackReference
private Accommodation accommodation;
....getters setters
}
When I execute a query for listing accommodations, I get unknown column in field list error.
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'bookings7_.bookings' in 'field list'
Even I set the relation and define the foreign key in table, what is the reason that I get this error?
Try to define your join-table mapping manually in JPA. Drop your schema and let JPA create your tables:
Accommodation class
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
Booking class
#ManyToOne(fetch = FetchType.EAGER)
#JoinTable(name = "accommodation_booking_join_table",
joinColumns = {#JoinColumn(name="booking_id")},
inverseJoinColumns = #JoinColumn(name = "accommodation_id"))
#JsonBackReference
private Accommodation accommodation;
Try changing your column names to lower case in your db and entity class.
I had a situation like that, and I solved it by changing the field's position on the query. Looks like it's a MySQL bug, like (or the same as) the one mentioned on this post:
https://bugs.mysql.com/bug.php?id=1689
The description of this MySQL bug mentioned a similar workaround solution: "I found that by swapping that field's position in the table with another field that it worked OK."
I am learning hibernate and stuck a bit with the below problem
have two tables
CREATE TABLE department (
department_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
caption varchar(255) DEFAULT NULL) ENGINE=InnoDB;
CREATE TABLE employee (
employee_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
fio varchar(255) DEFAULT NULL,
fk_department_id int(11) NOT NULL,
FOREIGN KEY (fk_department_id) REFERENCES department (department_id)
) ENGINE=InnoDB ;
and two classes (in the first class commented out code looks like working solution)
#Entity
#Table(name = "department")
public class Department {
....
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "employee", joinColumns = {
#JoinColumn(name = "fk_department_id", referencedColumnName = "department_id") })
/*
* #OneToMany(fetch = FetchType.LAZY, mappedBy = "department", cascade =
* CascadeType.ALL)
*/
public Set<Employee> getEmployies() {
return employees;
}
#Entity
#Table(name = "employee")
public class Employee {
......
#ManyToOne
#JoinColumn(name = "fk_department_id")
public Department getDepartment() {
return department;
}
this results into
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
Exception in thread "main" org.hibernate.MappingException: Foreign key (FK3cspe1b06hmsik5l8y1i11xmd:employee [employies_employee_id])) must have same number of columns as the referenced primary key (employee [fk_department_id,employies_employee_id])
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:148)
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:130)
Please help me to understand why this doesn't work
The following should work just fine. You'll notice I am not specifying any join column relations because I am allowing Hibernate to generate those automatically for me.
#Entity
public class Department {
#OneToMany
#JoinTable(name = "department_employees")
private List<Employee> employees;
}
#Entity
public class Employee {
#ManyToOne
private Department department;
}
But lets assume you want to be explicit about the join columns.
#Entity
public class Department {
#Id
#Column(name = "department_id")
private Integer id;
#OneToMany
#JoinTable(
name = "department_employees",
joinColumns = #JoinColumn(name = "department_id"),
inverseJoinColumns = #JoinColumn(name = "employee_id"))
private List<Employee> employees;
}
#Entity
public class Employee {
#Id
#Column(name = "employee_id")
private Integer id;
#ManyToOne
#JoinTable(
name = "department_employees",
joinColumns = #JoinColumn(name = "department_id", insertable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "employee_id", insertable = false, updatable = false))
private Department department;
}
The key points to take away from this are:
The name of the join table specifies the middle table that maintains the relationship between the Department and Employee entities. It should not refer to the Employee table as your code illustrates.
The joinColumns attribute represents the primary key attributes of the containing entity, in this case that is Department, hence I used department_id.
The inverseColumns attribute represents the primary key attributes of the associated entity, in this case that is Employee, hence I used employee_id.
Update:
If you'd like to eliminate the #JoinTable and merely maintain the relationship between Department and Employee, you'd change your mappings as follows:
#Entity
public class Department {
#OneToMany(mappedBy = "department")
private List<Employee> employees;
}
#Entity
public class Employee {
#ManyToOne
private Department department;
}
Hope that helps.
I have a ManyToMany relation between two entity
#javax.persistence.Entity
#Table(name = "t_aircraft_model")
public class AircraftModel extends DbObject {
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name = "t_aircraft_model_entity", joinColumns = { #JoinColumn(name = "aircraft_model_uid", nullable = false) }, inverseJoinColumns = { #JoinColumn(name = "entity_id_LDAP", nullable = false) })
private List<com.airbushelicopter.ahead.db.pojo.Entity> entities ;
But sqlServer doesn't allow me to publish the intermediate table : t_aircraft_model_entity
I thought about 2 solutions
Both column of the table the t_aircraft_model_entity become the primary key (ok in my case a aircraft can't be linked multiple time to the same entity)
I add a 3rd column (id) which will be the primary key
Or ?
But I have no idea how I can do this with hibernate and annotation.
thanks !
First things first. You will need 3 tables to make a many to many relation, of course, you will need to make sure that both of your other tables have a PK
On the code side, you can do like this:
Your Airplace Model:
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "t_aircraft_entity_relation",joinColumns = {
#JoinColumn(name = "aircraftid", nullable = false, updatable = false)},
inverseJoinColumns = { #JoinColumn(name = "entityid",nullable = false,updatable= false)
})
private Set<com.airbushelicopter.ahead.db.pojo.Entity> entities ;
On your Entity Model:
#ManyToMany(fetch = FetchType.EAGER,mappedBy="entities")
private Set<AircraftModel> aircrafts;
And you will have to create a relation table, like in my example:
CREATE TABLE t_aircraft_entity_relation
(
aircraftid integer NOT NULL,
entityid integer NOT NULL,
CONSTRAINT "PK_AIRCRAFT_ENTITY" PRIMARY KEY (aircraftid, entityid),
CONSTRAINT "FK_AIRCRAFT_ENTITY" FOREIGN KEY (aircraftid)
REFERENCES t_aircraft_model (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT "FK_ENTITY_AIRCRAFT" FOREIGN KEY (entityid)
REFERENCES t_entity_model (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
PS: This piece of SQL is based on Postgresql, so you will have to do a little bit of change.
I'm trying to map entity-key with entity-value map to database using JPA2.1 and Hibernate 4.3.7.
Here's my code:
#Entity
#Audited
class Form{
//id
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "form_content",
joinColumns = #JoinColumn(name = "id_form", nullable = false),
inverseJoinColumns = #JoinColumn(name = "id_field_content"/*non-working part start*/, unique = false, nullable = true/*non-working part stop*/),
uniqueConstraints = { #UniqueConstraint(columnNames = { "id_field", "id_form" }) })
#MapKeyJoinColumn(name = "id_field", nullable = false)
private Map<FormEntryDefinition, FormEntryValue> content;
//getters, setters, equals, etc.
}
Hibernate generates table
form_content(
id_form bigint primary key not null,
id_field_content bigint <!-- problem start -->not null unique <!--problem stop -->,
id_field bigint primary key not null)
with proper foreign keys in all 3 fields.
Could anyone tell me, why hibernate generates unique and not null constraints, so I can't persist map with nullable value?
Is there any workaround for that problem?
The unique constraint is due to using a #OneToMany association. If you change it to #ManyToMany then the unique constraint would no longer be necessary.
The join table FK columns only make sense for non-nullable columns. A row in the join table is a link between two tables, and if one FK is missing then the association breaks anyway and it's equivalent to not having a link row in the first place.