A. I have a entity EntityA like below:
Table - EntityA(id long PK, name varchar)
#Entity #Table
EntityA{
#Id
long id;
String name;
}
B. Based on this I want to fetch data in below class through JPA(using unidirectional mapping):
#Entity #Table
EntityMap{
long id;
#OneToOne
EntityA entity;
#OneToMany
List<EntityA> mappedEntity;
}
C. To make it work for now I have created an entity like below:
Table - entity_map(id long pk, source_entity_id long FK-EntityA_id, target_entity_id long FK-EntityA_id)
#Entity #Table
EntityMap{
#Id
long id;
#OneToOne
#JoinColumn(name = "source_entity_id")
EntityA sourceEntity;
#ManyToOne
#JoinColumn(name = "target_entity_id")
EntityA targetEntity;
}
This is working as expected but I need entity explained in #B. Any suggestion?
A #OneToMany relationship can be archieved by
#JoinColumn(name = "entity_map_id")
#OneToMany
List<EntityA> mappedEntity;
In your EntityA table you need a column entity_map_id and a foreign key (entity_map_id) references EntityMap(id) constraint.
If you cannot change the EntityA table you need a #JoinTable to perform the mapping:
#JoinTable(name = "JOIN_TABLE", joinColumns = {#JoinColumn(name = "MY_ENTITY_MAP_FK")}, inverseJoinColumns = {#JoinColumn(name = "ENTITY_A_FK")})
#OneToMany
List<EntityA> mappedEntity;
The join table contains two columns ENTITY_A_FK and MY_ENTITY_MAP_FK:
create table JOIN_TABLE(
ENTITY_A_FK integer not null,
MY_ENTITY_MAP_FK integer not null
);
Related
There's a table with a "FK" column whose values might point back to either TableA or TableB, something like this:
CREATE TABLE TableC (
"id" bigint GENERATED BY DEFAULT AS IDENTITY,
"linked_entity_id" integer,
"linked_entity_type" varchar(15),
...other columns
PRIMARY KEY ("id")
);
I'm struggling with representing this in JPA. I'd like to have both TableA and TableB entities in JPA to have a List. Is there a way to do this?
This is my attempt, having TableC entity modeled like this:
#Entity
public class TableC {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long linkedEntityId;
#Enumerated(EnumType.STRING)
private LinkedEntityType linkedEntityType;
#ManyToOne
#JoinColumn(name = "linked_entity_id", referencedColumnName = "id", insertable=false, updateable=false)
private TableA tableA;
#ManyToOne
#JoinColumn(name = "linked_entity_id", referencedColumnName = "id", insertable=false, updateable=false)
private TableB tableB;
}
But, what happens when the TableC has a row whose id in the linked_entity_id column belongs to TableA id not to TableB? I think an exception would be thrown.
PS: TableA and TableB do not have anything in common.
You must use the #Where annotation:
#ManyToOne
#Where(clause = "linked_entity_type = 'TableA'")
#JoinColumn(name = "linked_entity_id", referencedColumnName = "id", insertable=false, updateable=false)
private TableA tableA;
#ManyToOne
#Where(clause = "linked_entity_type = 'TableB'")
#JoinColumn(name = "linked_entity_id", referencedColumnName = "id", insertable=false, updateable=false)
private TableB tableB;
Source: https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#pc-where
I want to join these 3 Tables.
Here you see my Person Entity
#Entity
#Table(name = "Person", schema = "public")
public class PatientEntity {
#Id
#Column(name = "id")
private Long id;
#Column(name = "lastname")
private String name;
#OneToMany
#JoinTable(name = "person_contact", joinColumns = { #JoinColumn(name = "person_id") }, inverseJoinColumns = { #JoinColumn(referencedColumnName = "id") })
#Column(name = "contact")
private Set<ContactEntity> contacts;
//Getter Setters
And here is my contact entity:
#Entity
#Table(name="contact",schema="public")
public class ContactEntity {
#Id
#Column(name="id")
private Long id;
#Column(name="phone")
private String phone;
//Getter Setters
I just read the Persons from the Table with findById with a Spring JPARepository, but there is no Contact mapped. There is no error during my HTTP request, but instead of a Contact there is null and this error message:
com.sun.jdi.InvocationException occurred invoking method.
The business case is, that every Person can have one or more contact. Is it possible to make it with JPA Annotations or do I need to map it by myself with a JPQL? Or should I create an Entity for the middle table? (person_contact)
The Database is a PostgreSQL Database.
There is this notification too in the Log:
ERROR: column contacts0_.contacts_id does not exist
Perhaps you meant to reference the column "contacts0_.contact_id".
Position: 306
Your #JoinTable has incorrect #JoinColumn specifications and corresponds to the following ddl.
create table person_contact (person_id bigint not null, contacts_id bigint not null, primary key (person_id, contacts_id))
To map your db structure, use following (note removed #Column annotation)
#OneToMany
#JoinTable(name = "person_contact", joinColumns =
{
#JoinColumn(name = "person_id", referencedColumnName = "id"),
},
inverseJoinColumns = {
#JoinColumn(name = "contact_id", referencedColumnName = "id")
})
private Set<ContactEntity> contacts;
I also encourage you to read https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ and reconsider a db structure without a join table (depending on your load and the effort to make this db change)
I am working with one-to-many relation using hibernate.
profesor.java
#Entity
public class Profesor {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
#ManyToMany(mappedBy = "profesors", fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
private List<Classes> classes;
#OneToMany(mappedBy="profesor", fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
#Fetch(value = FetchMode.SUBSELECT)
private List<Post> post;
}
My professor table is already in relation with classes table as many-to-many. Now I am trying to connect it with post table as one-to-many.
My post model looks like this:
post.java
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn (name="profesor_id",referencedColumnName="id",nullable=false,unique=true)
private Profesor profesor;
}
Here is how my table post looks in database.
I am getting following error:
Cannot add or update a child row: a foreign key constraint fails (`database`.`#sql-45e3_695`, CONSTRAINT `FKfkqyncksuk5vuw09wam4sryyd` FOREIGN KEY (`profesor_id`) REFERENCES `profesor` (`id`))
What am I doing wrong?
SOLUTION:
First I created post table without profesor_id. I added profesor_id when I started to create relationship between tables and then profesor_id was set to null. When I cleared my table I could run my application normally.
its clear you are violating some constraint, i would say you are trying to remove a proffesor which is already linked to post, try to remove nullable = false
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn (name="profesor_id",referencedColumnName="id",unique=true)
private Profesor profesor;
How can I use #JoinTable to join three tables?
I have three tables:
user:
id, name
post:
id, date
company:
id, name
I want to create a new table with the following columns:
user_id, post_id, company_id.
I used:
#JoinTable(name = "new_table", joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "post_id"))
However, I am not sure how to add the third column.
You must not will use #JoinTable annotation. The #JoinTable annotation is used only to #ManyToMany relationship.
You need create a new Entity with three field, and each field must has the #ManyToOne and #JoinColumn annotation.
For Instance:
#Entity
#Table(name = "table_name")
class NewEntity {
//Id and anothers fields
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "post_id")
private Post post;
#ManyToOne
#JoinColumn(name = "company_id")
private Company company;
//getters and setters
}
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."