Hibernate #OneToMany without a separate join table - java

Consider the following database schema:
create table UserGroup ( id int not null auto_increment, name varchar(200),
primary key(id));
create table User ( id int not null auto_increment, name varchar(200),
groupId int not null, primary key(id));
User.groupId = UserGroup.id, so a user can only be a member of one group, but a usergroup can exist of many users. Fine so far, let's make the entities in Hibernate. Here's User:
#Entity
#Table(name = "User")
public class User {
#Id
#Column(name="id", nullable = false)
private Integer id;
#Column(name="name", length = 200, nullable = true)
private String name;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "groupId", nullable = false, insertable=false, updatable=false)
#ForeignKey(name="FK_GroupId")
private UserGroup userGroup;
/* Getters, Setters, toString, equals & hashCode */
}
Here's UserGroup:
#Entity
#Table(name = "UserGroup")
public class UserGroup {
#Id
#Column(name="id", nullable = false)
private Integer id;
#Column(name="name", length = 200, nullable = true)
private String name;
#OneToMany(fetch=FetchType.EAGER)
private List<User> users;
/* Getters, Setters, toString, equals & hashCode */
}
Now I'll get an error "Table mydb.usergroup_user' doesn't exist" because it expects a join-table. My data structure is "set in stone" due to interoperability with other applications that this application will replace, so I won't be making a join-table. Also, it should not be needed. How can I make a List<User> users that simply is a list of User where User.groupId == UserGroup.Id?

I think you need the mappedBy="UserGroup" in the #OneToMany annotation.

Related

Repeated column in mapping for entity in #OneToOne

I have two tables:
CREATE TABLE users
(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(68) NOT NULL,
oldPassword VARCHAR(68),
enabled BOOLEAN NOT NULL
);
and
CREATE TABLE authorities (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL,
FOREIGN KEY (username) REFERENCES users(username)
);
CREATE UNIQUE INDEX ix_auth_username on authorities (username,authority);
Unfortunatelly instead of joining with authority_id which should be in users table I just have username which is the same in both tables.
In models I tried (ommited getters and setters):
#Entity(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String oldPassword;
private boolean enabled;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "username", referencedColumnName = "username")
private Authorities authority;
}
and
#Entity
public class Authorities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String authority;
#OneToOne(mappedBy = "authority")
private User user;
}
but then I have an error: Repeated column in mapping for entity column: username (should be mapped with insert="false" update="false")
The reason you are getting usernames in both tables is that you have declared username column in both the tables.
Also, you have to map the relation based on the authority_id so the code of the models would look like this:
#Entity(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String oldPassword;
private boolean enabled;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "authority_id", referencedColumnName = "id")
private Authorities authority;
}
#Entity
public class Authorities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String authority;
#OneToOne(mappedBy = "authority")
private User user;
}
And the tables will be created like this:
Hope this solves your problem.
The message is clear: you have a repeated column in the mapping, and a column "username" in both tables has repeated. Instead of this, you should use this :
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "authority_username", referencedColumnName = "username")
private Authorities authority;

OneToMany mapping on table with composite key returns empty list

I have been struggled into OneToMany mapping on entity with composite primary key when I try to get List of items of child table.
I have entitties Person and PhoneNumbers. One person may have multiple phone numbers. PhoneNumber entity have primary key consist of two fields: id and person_id which is foreign key to Person entity.
This is a database schema:
person:
id (pk)
person_name
phone_number:
id (pk)
person_id (pk)(fk)
phone_number
Person class
#Entity(name = "person")
public class Person {
#Id
#Column(name = "id")
private Long id;
#Column(name = "person_name")
private String name;
#OneToMany(mappedBy = "person")
private List<PhoneNumber> phoneNumbers;
// constructor, getters, setters...
}
PhoneNumber class
public class PhoneNumber {
#EmbeddedId
private PhoneNumberPk phoneNumberPk;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id", insertable = false, updatable = false)
private Person person;
#Column(name = "phone_number")
private String phoneNumber;
// constructor, getters, setters...
}
PhoneNumberPk class
#Embeddable
public class PhoneNumberPk {
#Column(name = "id")
private Long id;
#Column(name = "person_id")
private Long personId;
// constructor, getters, setters...
}
Problem is when I get Person entity from database and call person.getPhoneNumbers() I always get empty list. Hibernate debugging shows that query that fetch data from phone_number table is executed when I call person.getPhoneNumbers() but I always get empty list.
I'm using Spring Boot - Spring Data JPA 2.0.7 and Hibernate 5.2.17

manyToOne and oneToMany in hibernate&spring

I have 2 tables in database side(oracle)
create table GROUPS
(
ID NUMBER not null,
GROUP_NAME VARCHAR2(30)
)alter table GROUPS
add constraint ID primary key (ID)
and
create table ITEM_GROUP
(
ITEM_ID VARCHAR2(30) not null,
GROUP_ID NUMBER not null
)
alter table ITEM_GROUP
add constraint ITEM_GROUPD_ID primary key (ITEM_ID, GROUP_ID)
alter table ITEM_GROUP
add constraint ITEM_GROUP_FK01 foreign key (GROUP_ID)
references GROUPS (ID);
Than I have mapping classes in Java side. I want to make thing, when I am selecting group to take all his items too, and I want to save item with hibernate it is all .
#Entity
#Table(name = "GROUPS")
public class Group {
#Id
#Column(name = "ID", nullable = false)
#javax.persistence.SequenceGenerator(name = "groupIdGenerator", sequenceName = "GROUP_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "groupIdGenerator")
private int id;
#Column(name = "GROUP_NAME")
private String groupName;
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER, mappedBy="group",cascade = CascadeType.ALL)
private List<GroupItems> groupItems = new ArrayList<>();
// setters and getters
}
#SuppressWarnings("serial")
#Embeddable
public class GroupItemPK implements Serializable {
#Column(name = "ITEM_ID")
private String merchantId;
#Column(name = "GROUP_ID")
private int id;
// getters , setters , constructors , equals hashcode methods
}
#Entity
#Table(name = "ITEM_GROUP")
public class GroupITEM {
#EmbeddedId
private GroupITEMtPK id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID")
#JsonBackReference
private Group group;
}
I am interested in did i make any mistakes in build relationship ? If I did what is my mistakes , because I can not do my select and save queries without exceptions.
I am trying to do in my Code
List<Group> list = sessionFactory.getCurrentSession().createQuery("from Group a").list();
and here is my Exception
org.hibernate.engine.jdbc.spi.SqlExceptionHelper could not extract ResultSet [n/a]
java.sql.SQLSyntaxErrorException: ORA-00904: "GROUPITE0_"."ID": invalid identifier

Persisting #ManyToOne with optional Foreign Keys?

I want to persist an #Entity having a #ManyToOne #JoinColumn reference, which should be optional.
But when I try to persist the following Person class where locationId is set, but address rerference is not set, I'm getting a PSQLException: voilates foreign key constraintsexception.
My class looks as follows:
#Entity
public class Person {
#Id
private Long id;
private String name;
private int locationId;
#ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.DETACH})
#JoinColumn(name = "location_id", foreignKey = #ForeignKey(name="fk_address"), nullable = true)
private AddressEntity address;
}
#Entity
public class AddressEnity {
#Id
private int locationId;
//street, zip, town etc
#OneToMany(mappedBy = "address")
private Set<Person> persons;
}
The schema generated by hibernate:
CREATE TABLE person(
id bigint NOT NULL,
name character varying(255),
location_id interger NOT NULL,
CONSTRAINT fk_address FOREIGN KEY (location_id)
REFERENCES addresses (location_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
CREATE TABLE address(
location_id integer NOT NULL,
//street, zip, town, etc
CONSTRAINT location_id_pk PRIMARY KEY (location_id)
);
Question: isn't is possible to save the locationId explicit, but omitting the address entity? (which might come in later, but not known at this stage).

How to define the association table as pojo entity

I have 3 tables in the db. I am trying to write the JPA entities. I am facing some issues with Association table entity. My entities are as follows,
Person.java
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
//setter and getter
}
Exam.java
#Entity
#Table(name = "exam")
public class Exam {
#Id
#GeneratedValue
private long examId;
#Column(nullable = false)
private String examName;
#Column(nullable = false)
private int marks;
//Setters and getters
}
The table structure for association table is,
create table person_exam (
personId BIGINT not null,
examId BIGINT not null,
primary key (personId, examId)
);
I tried the association table entity with #ManyToMany annotation for both the properties which is not giving me the result.
Can anyone please suggest me what should I need to use (ManyToMany/OneToOne/ManyToOne/OneToMany ) in my entity for the above person_exam table.
from the PRO JPA 2nd Ed. book:
the only way to implement a many-to-many relationship is with a separate join table. The consequence of not having any join columns in either of the entity tables is that there is no way to determine which side is the owner of the relationship. Because every bidirectional relationship has to have both an owning side and an inverse side, we must pick one of the two entities to be the owner.
So I chose the the Person entity. Applying the needed changes to your incomplete code:
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
/**
* we need to add some additional metadata to the Person designated
* as the owner of the relationship, also you must fully specify the names of
* the join table and its columns because you already provided a schema
* for the association table, otherwise the JPA provider would generate one.
*/
#ManyToMany
#JoinTable(name="person_exam",
joinColumns=#JoinColumn(name="personId"),
inverseJoinColumns=#JoinColumn(name="examId"))
private Collection<Exams> exams;
//setter and getter
}
#Entity
#Table(name = "exam")
public class Exam {
#Id
#GeneratedValue
private long examId;
#Column(nullable = false)
private String examName;
#Column(nullable = false)
private int marks;
//Setters and getters
/**
* As in every other bidirectional relationship,
* the inverse side must use the mappedBy element to identify
* the owning attribute.
*/
#ManyToMany(mappedBy="exams")
private Collection<Person> people;
}

Categories