JPA #ManyToOne joining on part of composite primary key - java

I have two tables that I want to join.
Lets say TableA and TableB.
TableA
#Entity
#Table(name = "TableA")
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class TableA {
#Id
#EmbeddedId
private TableA.PrimaryId id = new TableA.PrimaryId();
#Column(name = "COL1")
private Integer col1;
#ManyToOne
#JoinColumn(name = "ID1")
private TableB tableB;
#Data
#Embeddable
#Builder
#AllArgsConstructor
#NoArgsConstructor
public static class PrimaryId implements Serializable {
#Column(name = "ID1")
private Integer id1;
#Column(name = "ID2")
private Integer id2;
}
}
TableB
#Entity
#Table(name = "TableB")
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class TableB {
#Id
#EmbeddedId
private PrimaryId id = new PrimaryId();
#Column(name = "COLUMN1")
private String column1;
#Data
#Embeddable
#Builder
#AllArgsConstructor
#NoArgsConstructor
public static class PrimaryId implements Serializable {
#Column(name = "ID1")
private Integer id1;
#Column(name = "KEY2")
private Integer key2;
#Column(name = "KEY3")
private Integer key3;
#Column(name = "KEY4")
private Long key4;
}
}
The problem is that TableB has composite primary key (4 columns), but I need to do join only on 1 column (ID1).
It isnt a standart join, it is a partial primary key join.
So it causes an error:
nested exception is org.hibernate.AnnotationException: A Foreign key refering TableB from TableA has the wrong number of column. should be 4
If I try this
#ManyToOne
#JoinColumn(name = "ID1", referencedColumnName = "ID1", updatable=false, insertable=false)
I get another error
nested exception is org.hibernate.AnnotationException: referencedColumnNames(ID1) of TableA.TableB referencing TableB not mapped to a single property
I've looked for an answer in similar posts but found nothing useful :(
So I appreciate any help...

Related

This class does not define an IdClass foreign key

I am using the productid as a foreign key in my phone table. I don't know what to write in the id part of the PhoneRepository. Because gives an error
Product.java
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Product {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private long productID;
...
Phone.java
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#IdClass(Product.class)
public class Phone implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#OneToOne
#JoinColumn(name = "productID")
private Product product;
...
PhoneRepository.java
#Repository
public interface PhoneRepository extends CrudRepository<Phone, Product>{ //I tried Long
}
Error
Caused by: java.lang.IllegalArgumentException: This class [class
com.test.project.data.entity.prod.Phone] does not define an IdClass
Remove the #IdClass annotation on Product because you are not customizing an id provider.
Also remove #Id from product on Phone and add a phoneID as below:
#Id
private long phoneID;
#OneToOne
#JoinColumn(name = "productID", referencedColumnName = "productID")
private Product product;

Hibernate AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class

I know this question has been raised many times before, but I am still confused where the mistake might be in my case:
AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: com.collab.collabplatform.persistance.entities.CategoryModel.category2projectRel[com.collab.collabplatform.persistance.keys.Category2ProjectRelKey]
CREATE TABLE IF NOT EXISTS `category2projectRel`
(
`project_id` bigint(20) NOT NULL,
`category_id` bigint(20) NOT NULL,
PRIMARY KEY (`project_id`, `category_id`),
CONSTRAINT `FK_category2project_project_id` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`),
CONSTRAINT `FK_category2project_category_id` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
and the entities and key classes:
#Entity
#Table(name = "\"category2projectRel\"")
#NoArgsConstructor
#Getter
#Setter
public class Category2ProjectRelModel {
#EmbeddedId
private Category2ProjectRelKey id;
#ManyToOne
#MapsId("project_id")
#JoinColumn(name = "project_id")
private ProjectModel project;
#ManyToOne
#MapsId("category_id")
#JoinColumn(name = "category_id")
private CategoryModel category;
}
&
#Getter
#Setter
#NoArgsConstructor
#Embeddable
public class Category2ProjectRelKey implements Serializable {
#Column(name = "project_id")
Long projectId;
#Column(name = "category_id")
Long categoryId;
}
&
#Entity
#Table(name = "\"category\"")
#NoArgsConstructor
#Getter
#Setter
public class CategoryModel extends BaseEntity {
#Column
#NotNull
private String title;
#Column
private String color;
#OneToMany(mappedBy = "category")
List<Category2ProjectRelKey> category2projectRel;
}
&
#Entity
#Table(name = "\"project\"")
#NoArgsConstructor
#Getter
#Setter
public class ProjectModel extends BaseEntity {
#ManyToOne
#JoinColumn(name="location_id")
private LocationModel location;
#NotNull
#Column
private String title;
#NotNull
#Column(name = "creation_date")
private OffsetDateTime creationDate;
#NotNull
#Column
private String status;
#Column(name = "termination_date")
private OffsetDateTime terminationDate;
#Column
private String description;
#Column
private Boolean virtual;
#OneToMany(mappedBy = "project")
List<Category2ProjectRelKey> category2projectRel;
#OneToMany(mappedBy = "project")
List<Project2TagRelKey> project2tagRel;
}
#ManyToOne #OneToMany #OneToOne #ManyToMany annotations should be used with Entity classes (classes annotated with #Entity)
So, in CategoryModel class, you use #OneToMany with class Category2ProjectRelKey, which is not an entity.
#OneToMany(mappedBy = "category") // this annotation should target an entity class
List<Category2ProjectRelKey> category2projectRel;
#Embeddable annotation on a class, does not mean it's an entity, but means that it represents a set of a column of more that could be included in other entities.

Composite primary key table not populating in related entity

My database contains a table with a composite-primary-key such that one of the keys is a foreign key, and the other is supposed to be used to get an entity from an external service. The code looks somewhat like this:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#Embeddable
#EqualsAndHashCode
public class PrimaryKey implements Serializable {
#Column(name = "A_ID")
private Long aId;
#Column(name = "F_ID")
private Long fId;
}
#Entity
#Table(name = "JOIN_ENTITY")
#Getter
#Setter
#EqualsAndHashCode
#AllArgsConstructor
#NoArgsConstructor
public class JoinEntity {
#EmbeddedId
private PrimaryKey pk;
#MapsId("aId")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "A_ID")
private EntityA a;
public getFId() { return pk.getFId(); }
}
#Entity
#Table(name = "ENTITY_A")
#Getter
#Setter
#EqualsAndHashCode
#AllArgsConstructor
#NoArgsConstructor
public class EntityA implements Serializable {
....
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL, orphanRemoval = true)
List<JoinEntity> list = new ArrayList<>();
}
When I get a JoinEntity saved and try to get EntityA from the database the list is not being populated, but if I get some JoinEntity from the database the related EntityA is recovered correctly. What do I do to get the JoinEntity list to be recovered with the EntityA?
You need to use FetchType.EAGER on the #OneToMany association in the EntityA class:
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
List<JoinEntity> list = new ArrayList<>();
This way when you retrieve a EntityA from the database, its JoinEntitys will be automatically retrieved.
Solved the problem adding an ENTITY_F table with the id and switching to a simple ManyToMany relationship.

Mapping a bidirectional One-to-Many Hibernate Entity with JPA

I am trying to map a bidirectional One-to-Many relationship in Hibernate. In the build logs I receive the error "repeated column in mapping for entity."
What is generating the error?
The entity source code is below. One has a compound primary key. I am using Lombok to generate getters and setters.
The relationship: Award (One) --> AwardReceived (Many)
Award Entity
#Entity
#Table(name = "awards")
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class Award implements Serializable {
#Id
#Column(name = "award_id")
private Long awardId;
#OneToMany(cascade=CascadeType.ALL, mappedBy = "award")
private Set<AwardReceived> awardsReceived;
#Column(name = "award_type")
private String awardType;
#Column(name = "award")
private String award;
#Column(name = "description")
private String description;
}
AwardReceived Entity
#Entity
#Table(name = "awards_received")
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class AwardReceived implements Serializable{
#EmbeddedId
#JsonUnwrapped
private AwardReceivedPk awardReceivedPk;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "award_id")
private Award award;
#Column(name = "award_name")
private String awardName;
#Column(name = "citation")
private String citation;
}
AwardReceivedPk
#Embeddable
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class AwardReceivedPk implements Serializable{
#JsonIgnore
#Column(name = "client_no")
private String clientNo;
#Column(name = "award_id")
private Long awardId;
#Column(name = "year")
private Long year;
}
Please try
#ManyToOne(cascade=CascadeType.ALL)
private Award award;
instead of
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "award_id")
private Award award;

Shared primary key generation. Hibernate

I'm having problems with generating primary keys with one-to-one relations that use shared primary key.
Here's code:
#Entity
#Table(name = "osoba")
public class Osoba implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "osoba_id")
private Integer osobaId;
#PrimaryKeyJoinColumn
#OneToOne(cascade = CascadeType.PERSIST)
public Pracownik pracownik;
...
and second class:
#Entity
#Table(name = "pracownik")
public class Pracownik
{
#OneToOne
#JoinColumn(name = "osoba_id")
#MapsId("osobaId")
private Osoba osoba;
#Id
#Column(name = "osoba_id")
private Integer osobaId;
...
I've been similar issues and I thought that i've done everything correctly but i still get
org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): entity.Pracownik
when trying to persist Pracownik objects.
You need to follow example from #MapsId documentation (in your case, with #Id instead of #EmbeddedId):
#Entity
#Table(name = "pracownik")
public class Pracownik {
#Id
#Column(name = "oboba_id")
private Integer id;
#OneToOne
#MapsId
private Osoba osoba;
...
}
Inverse side of #OneToOne relationship should be mapped with mappedBy, as usually:
#Entity
#Table(name = "osoba")
public class Osoba implements Serializable {
...
#OneToOne(mappedBy = "osoba", cascade = CascadeType.PERSIST)
public Pracownik pracownik;
...
}
This old question but it works for me. Mayby it will help someone.
SQL Script (Oracle)
DROP TABLE HIBERNATE.PRACOWNIK;
DROP TABLE HIBERNATE.OSOBA;
DROP SEQUENCE HIBERNATE.OSOBA_SEQ;
CREATE TABLE HIBERNATE.OSOBA (
osoba_id NUMBER(15),
CONSTRAINT OSOBA_PK PRIMARY KEY (osoba_id)
);
CREATE TABLE HIBERNATE.PRACOWNIK (
pracownik_id NUMBER(15),
CONSTRAINT PRACOWNIK_PK PRIMARY KEY (pracownik_id),
CONSTRAINT PRACOWNIK_FK FOREIGN KEY (pracownik_id) REFERENCES OSOBA(osoba_id)
);
CREATE SEQUENCE HIBERNATE.OSOBA_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
Osoba.java
#Entity
#Table(name = "osoba")
public #Data class Osoba {
#Id
#Column(name = "osoba_id")
#GeneratedValue(generator="osoba-generator", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name="osoba-generator", allocationSize = 1, sequenceName = "OSOBA_SEQ")
private Long osobaId;
#OneToOne(fetch=EAGER, mappedBy="osoba", cascade=ALL)
private Pracownik pracownik;
}
Pracownik.java
#Entity
#Table(name="pracownik")
public #Data class Pracownik {
#Id
#Column(name = "pracownik_id")
#GeneratedValue(generator="pracownik-generator")
#GenericGenerator(name="pracownik-generator", strategy="foreign", parameters=
#Parameter(name = "property", value = "osoba")
)
private Long pracownikId;
#OneToOne(fetch=FetchType.EAGER)
#PrimaryKeyJoinColumn
private Osoba osoba;
}
#Data is Lombok

Categories