Student entity:
#Entity
#Table(
name = "student"
)
public class Student implements Comparable<Student> {
#Id
#Column(
name = "id"
)
private Integer id;
#Column(
name = "name"
)
private String name;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(
name = "id",
referencedColumnName = "student_id"
)
private StudentCard studentCard;
.................................getter and setter below.........................
StudentCard entity:
#Entity
#Table(
name = "student_card"
)
public class StudentCard {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
private Integer id;
#Column(
name = "balance"
)
private Integer balance;
....................................getter and setter below.........................
I have two tables created, student and student card. Both tables have a column named id as their primary key, but I am not trying to map them together.
I created a foreign key in the student card table where column student_id is tied with column id from student table. The owner is student card. However, after I created key and annotation, the hibernate still map to the wrong key when I tried to pull out the card information for each student.
For student table, the id is the primary key, whereas the student_id in card table is not. When I call for the student information in the controller side, I get a message of :
Hibernate:
select
studentcar0_.id as id1_1_0_,
studentcar0_.balance as balance2_1_0_,
studentcar0_.student_id as student_3_1_0_
from
student_card studentcar0_
where
studentcar0_.id=?
and this is the wrong map, because I am not mapping student.id=studentcard.id
I tried to switch column/referencecolumn name and it gave me an error of Unknown column 'student_id' not in field list. so I am not sure what should I do at this point.
Related
I need to map with JPA the following legacy DB table structure I cannot change.
It’s a one to many relationship between table ao_rda_acq (1) -> ao_rda_acq_righe (many) (purchase requisition -> purchase requisition rows)
Table (1)
create table ao_rda_acq
(
id_divisione varchar(4) not null,
esercizio smallint not null,
id_rda varchar(10) not null,
...
other fields
...
constraint pk_ao_rda_acq
primary key (id_divisione, esercizio, id_rda)
)
table many
create table ao_rda_acq_righe
(
id_divisione varchar(4) ,
esercizio smallint not null,
id_rda varchar(10) not null,
nr_riga integer not null,
...
other fields
...
constraint pk_ao_rda_righe
primary key (id_divisione, esercizio, id_rda, nr_riga),
constraint ao_rda_acq_righe_ao_rda_acq_id_divisione_esercizio_id_rda_fk
foreign key (id_divisione, esercizio, id_rda) references ao_rda_acq
)
The primary key of table ao_rda_acq side one of the relationship has 3 fields id_divisione, esercizio, id_rda. The primay key of the table side many of the relationship has the same 3 filed plus a 4th field nr_riga.
I tryed with this JPA approch using #IdClass annotation for composite primary keys
#Table(name="ao_rda_acq")
#Entity
#IdClass(RdaId.class)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Rda {
#Id
public String idDivisione;
#Id
public Integer esercizio;
#Id
public String idRda;
#OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
#JoinColumns({
#JoinColumn(name="id_divisione", referencedColumnName = "id_divisione"),
#JoinColumn(name="esercizio", referencedColumnName = "esercizio"),
#JoinColumn(name="id_rda", referencedColumnName = "id_rda")
})
#OrderBy("nrRiga")
public List<RdaRiga> righe = new ArrayList<>();
//Additional fields
}
where
public class RdaId implements Serializable {
String idDivisione;
Integer esercizio;
String idRda;
}
The entity for the rows is
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
#IdClass(RdaRigaId.class)
#Table(name = "ao_rda_acq_righe")
public class RdaRiga {
#Id
public String idDivisione;
#Id
public Integer esercizio;
#Id
public String idRda;
#Id
public Long nrRiga;
//More fields
}
where
public class RdaRigaId implements Serializable {
String idDivisione;
Integer esercizio;
String idRda;
Long nrRiga;
}
This code compiles but JPA at start-up complains with this message
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.DuplicateMappingException: Table [ao_rda_acq_righe] contains physical column name [id_divisione] referred to by multiple logical column names: [id_divisione], [idDivisione]
Is this approch the best one to map my unhappy DB structure? If so what did I miss?
When you use #Id without the #Column annotation, the name of the column is assumed to be the name of the annotated property.
Given that your DB column seems to be *id_divisione* you need to use also the annotation #Column(name = "id_divisione").
This also applies to the other properties annotated with #Id.
I'm new to Hibernate and I'm trying to establish a OneToMany/ManyToOne bidirectional relationship between Person and Vehicle classes. In my example a Person can have many Vehicles and a Vehicle belongs to only one Person. I need a join table: PERSON_VEHICLE with PERSON_ID and VEHICLE_ID as columns and a PERSON_ID column in VEHICLE table. Here's my class design:
Person class:
#Entity
public class Person {
#Id
#GeneratedValue
#Column(name = "PERSON_ID")
private int id;
private String name;
#OneToMany(cascade=CascadeType.ALL, mappedBy="person")
private Collection<Vehicle> vehicleList = new ArrayList<>();
Vehicle class:
#Entity
public class Vehicle {
#Id
#GeneratedValue
#Column(name = "VEHICLE_ID")
private int id;
private String name;
#ManyToOne
#JoinColumn(name="PERSON_ID")
#JoinTable(name="PERSON_VEHICLE", joinColumns=#JoinColumn(name="VEHICLE_ID"),
inverseJoinColumns=#JoinColumn(name="PERSON_ID"))
private Person person;
Here are the DDLs generated by Hibernate.
create table Person (
PERSON_ID integer not null auto_increment,
name varchar(255),
primary key (PERSON_ID)
)
create table Vehicle (
VEHICLE_ID integer not null auto_increment,
name varchar(255),
primary key (VEHICLE_ID)
)
create table PERSON_VEHICLE (
PERSON_ID integer,
VEHICLE_ID integer not null,
primary key (VEHICLE_ID)
)
alter table PERSON_VEHICLE
add index FK_h3d046x5uvbo53p8ms41hwqx (PERSON_ID),
add constraint FK_h3d046x5uvbo53p8ms41hwqx
foreign key (PERSON_ID)
references Person (PERSON_ID)
alter table PERSON_VEHICLE
add index FK_mtm2mn29hel3lbpl6i526w40v (VEHICLE_ID),
add constraint FK_mtm2mn29hel3lbpl6i526w40v
foreign key (VEHICLE_ID)
references Vehicle (VEHICLE_ID)
The VEHICLE table doesn't have PERSON_ID column. Something is wrong but I cannot find what the problem is.
Join table is not required for oneToMany relationship. Only two tables Person and Vehicle is sufficient for this mapping. For detailed example, see This Example
Given entity with embedded id and embedded foreign key:
#Entity
public class One {
#EmbeddedId
private ModelId id;
#Embedded
#AttributeOverride(name = "id", column = #Column(name = "two_id"))
private ModelId twoId;
}
#Embeddable
public class ModelId {
private Integer id;
}
when in JPQL:
SELECT o.id FROM One o WHERE o.twoId IN :twoId
then JPA generates SQL:
SELECT id FROM one WHERE id IN (?)
instead of:
SELECT id FROM one WHERE two_id IN (?)
How to make it work?
put the keys inside ModelID entity and use a reference of it as PK inside entity One:
#Entity
public class One {
#EmbeddedId
protected ModelId modelPK;
//getter and setter
}
public class ModelId {
#column(name="id")//give the real column name
private int id;
#column(name="towID")//give the real column name
private int twoId;
//getters and setters
}
and then use below JPQL query:
SELECT o.modelPK.id FROM One o WHERE o.modelPK.twoId=:twoId
I am trying to create OneToOne relation between a Person and Auth table. The problem is when the DB table "Auth" is generated, I'm not seeing the foreign key in the AUTH table that should reference Person. The object is to have the Auth table use the same Primary Key of the Person Table.
#MappedSuperclass
public abstract class DomainBase {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Version
#Column(name="OPLOCK")
private Integer version;
}
#Entity
#Table(name = "person")
public class Person extends DomainBase {
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="auth_id")
private Auth auth;
}
#Entity
public class Auth {
#Id
#GeneratedValue(generator="foreign")
#GenericGenerator(name="foreign", strategy = "foreign", parameters={
#Parameter(name="property", value="person")
})
#Column(name="person_id")
private int personId;
---------------------------------
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Person person;
}
My Database scripts after hibernate DB generation.
CREATE TABLE auth
(
person_id integer NOT NULL,
activate boolean,
activationid character varying(255),
last_login_attempt_date timestamp without time zone,
last_login_attempt_timezone character varying(255),
last_login_date timestamp without time zone,
last_login_timezone character varying(255),
nonlocked boolean,
num_login_attempts integer,
CONSTRAINT auth_pkey PRIMARY KEY (person_id),
CONSTRAINT uk_d68auh3xsosyrjw3vmwseawvt UNIQUE (activationid)
)
WITH (
OIDS=FALSE
);
ALTER TABLE auth
OWNER TO postgres;
It seems that the problem is you declare twice the #OneToOne annotation between "person" table and "auth" table, without specify the relation between them. Take a look at the hibernate documentation, at the point 2.2.5.1, there is some examples about using one-to-one association.
For me, the best way is to set up the association in one table, the one that declare the foreing key column, and to use the mappedBy parameter in the other object. In your code, this will be :
#Entity
#Table(name = "person")
public class Person extends DomainBase {
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="auth_id")
private Auth auth;
}
#Entity
public class Auth {
#Id
#GeneratedValue(generator="foreign")
#GenericGenerator(name="foreign", strategy = "foreign", parameters={
#Parameter(name="property", value="person")
})
#Column(name="person_id")
private int personId;
#OneToOne(mappedBy = "auth")
private Person person;
....
}
This is the second example in the hibernate documentation, introduce just after the sentence "In the following example, the associated entities are linked through an explicit foreign key column". I tested this code, and the "auth_id" column appeared.
I have defined a collection in Hibernate like this:
...
public class Item {
...
#ElementCollection
List<Object> relatedObjects;
}
It creates a mapping table with colums item_id and object_id.
The problem is that object_id seems to be unique. In other words I can not have two different items being related to the same object. But that is what I want.
I would like the combination of item_id and object_id to be unique. How do I do that?
That's not what I'm experiencing. For the following entity:
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue
private Integer id;
private String firstName;
private String lastName;
#Enumerated(EnumType.STRING)
private Gender gender;
#ElementCollection
private Set<String> nicknames = new HashSet<String>();
private String dept;
// getters, setters
}
The following tables get created:
create table Person (id integer generated by default as identity, dept varchar(255), firstName varchar(255), gender varchar(255), lastName varchar(255), primary key (id))
create table Person_nicknames (Person_id integer not null, nicknames varchar(255))
alter table Person_nicknames add constraint FK24F0D97B19ACB65E foreign key (Person_id) references Person
There is no unique constraint. But I can't say more without seeing your "Object" class (it's an embeddable class, right?).
PS: ElementCollection can't be a ManyToMany, this is more a OneToMany.