manyToOne and oneToMany in hibernate&spring - java

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

Related

JPA mappedBy reference an unknown target entity

I am writing a simple inventory database that contains tables for products, orders and customers. The database definition can be found here:
CREATE TABLE public.customers
(
id integer NOT NULL DEFAULT nextval('customers_id_seq'::regclass),
title character varying(10) COLLATE pg_catalog."default" NOT NULL,
first_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
middle_names character varying(50) COLLATE pg_catalog."default",
last_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
email character varying(50) COLLATE pg_catalog."default" NOT NULL,
phone_number character varying(50) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT customers_pkey PRIMARY KEY (id)
)
CREATE TABLE public.products
(
id integer NOT NULL DEFAULT nextval('products_id_seq'::regclass),
name character varying(100) COLLATE pg_catalog."default" NOT NULL,
sku integer NOT NULL,
inventory_on_hand integer NOT NULL,
reorder_threshold integer NOT NULL,
price numeric(5,2),
inventory_to_be_shipped integer NOT NULL,
CONSTRAINT products_pkey PRIMARY KEY (id)
)
CREATE TABLE public.order_items
(
id integer NOT NULL DEFAULT nextval('order_items_id_seq'::regclass),
product_id integer NOT NULL,
order_id integer NOT NULL,
CONSTRAINT order_items_pkey PRIMARY KEY (id),
CONSTRAINT order_items_order_id_fkey FOREIGN KEY (order_id)
REFERENCES public.orders (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT order_items_product_id_fkey FOREIGN KEY (product_id)
REFERENCES public.products (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
CREATE TABLE public.orders
(
id integer NOT NULL DEFAULT nextval('orders_id_seq'::regclass),
customer_id integer,
order_date date NOT NULL DEFAULT now(),
arrival_date date,
CONSTRAINT orders_pkey PRIMARY KEY (id),
CONSTRAINT orders_customer_id_fkey FOREIGN KEY (customer_id)
REFERENCES public.customers (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
I am trying to implement a Spring Security Resource server to perform CRUD operations on the database. I have implemented entity classes for each table in the database but when try to start the server I get a
org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: edu.finalyearproject.imsresourceserver.models.Order.customers in edu.finalyearproject.imsresourceserver.models.Customer.orders
My entity and repository classes can be found below:
Product.java:
#Entity
#Table(name = "products")
#Data
public class Product
{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer sku;
private Float price;
private Integer inventory_on_hand;
private Integer reorder_threshold;
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
#JoinTable(
name = "order_items",
joinColumns = #JoinColumn(name = "product_id"),
inverseJoinColumns = #JoinColumn(name = "order_id")
)
private Set<Order> orders = new HashSet<>();
}
Customer.java
#Entity
#Table(name = "customers")
#Data
public class Customer
{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
private String title;
private String first_name;
private String middle_names;
private String last_name;
private String email;
private String phone_number;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Order> orders;
}
Order.java
#Entity
#Table(name = "orders")
#Data
public class Order
{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name="customer_id", nullable=false)
private Customer customer;
private Date order_date;
private Date arrival_date;
#ManyToMany(mappedBy = "orders", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<Product> products = new HashSet<>();
}
I know the problem is related to the relationships between the entities, but I haven't been able to find a solution. Any help would be greatly appreciated.
Try to correct this:
#Entity
public class Customer
{
// ...
#OneToMany(mappedBy = "orders", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Order> orders;
}
to this:
#Entity
public class Customer
{
// ...
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Order> orders;
}
See additional explanation in the documentation.
And you should correct also your Product-Order #ManyToMany association. Only one side of this association should use #JoinTable other side should use mappedBy property of the #ManyToMany annotation. Something like this:
#Entity
public class Product
{
// ...
#ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.LAZY
)
#JoinTable(
name = "order_items",
joinColumns = #JoinColumn(name = "product_id"),
inverseJoinColumns = #JoinColumn(name = "order_id")
)
private Set<Order> orders = new HashSet<>();
}
#Entity
public class Order
{
// ...
#ManyToMany(
mappedBy = "orders",
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.LAZY)
private Set<Product> products = new HashSet<>();
}
As it is stated in the documentation:
For #ManyToMany associations, the REMOVE entity state transition doesn’t make sense to be cascaded because it will propagate beyond the link table. Since the other side might be referenced by other entities on the parent-side, the automatic removal might end up in a ConstraintViolationException.
Also as this is explained in this section of the documentation:
If you forget to JOIN FETCH all EAGER associations, Hibernate is going to issue a secondary select for each and every one of those which, in turn, can lead to N+1 query issues.
For this reason, you should prefer LAZY associations.

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

Not able to save data using OneToOne mapping

I am trying to save data in two table using OneToOne mapping.I have followed
this,this,this,this and few more online resources to accomplish this, but it is throwing
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
Creating a table where column TESTID is foreign key. In the parent table TESTID is primary key.That primary key is generated using sequence generator
CREATE TABLE EW_TEST_REFTABLE (
ID int NOT NULL PRIMARY KEY,
TESTNAME VARCHAR2(20) NOT NULL,
TESTID int,
CONSTRAINT test_id FOREIGN KEY(TESTID)
REFERENCES EW_TESTDATA(TESTID)
);
Ew_testdataEntity.java (Entity class of parent table)
#Entity
#Table(name = "EW_TESTDATA")
public class Ew_testdata {
#Id
#SequenceGenerator(name = "sube_seq",
sequenceName = "EW_TESTDATA_SEQ",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sube_seq")
#Column(name = "TESTID")
private int testid;
#Column(name = "TESTNAME")
private String testname;
// Ew_test_reftable is another entity class.In that table the column
// TESTID (foreign key) must be same as the primary key of this
// entity/table(EW_TESTDATA)
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_test_reftable ewtestreftable;
//Constructor
// getter & setter
}
Ew_test_reftable.java
#Entity
#Table(name = "EW_TEST_REFTABLE")
public class Ew_test_reftable {
#Id
#SequenceGenerator(name = "subf_seq", sequenceName = "EW_REF_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subf_seq")
#Column(name = "ID")
private int id;
#Column(name = "TESTNAME")
private String testname;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
//Constructor,getter & setter
}
Service to save data using Jpa
#Override
public Ew_testdata ew_testdata(String name) {
Ew_test_reftable ew_test_reftable = new Ew_test_reftable();
ew_test_reftable.setTestname("test");
Ew_testdata ew_testdata = new Ew_testdata();
ew_testdata.setTestname(name);
ew_testdata.setEwtestreftable(ew_test_reftable);
iew_tEst.ewTestdata(ew_testdata);
return null;
}
The problem seems to be similar to few other problem described in SO but still i am not able to figure out where I am making mistake
Your entity and table structure looks opposite, and that making so much confusion to understand.
Now, referring to exception
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
This mean, you don't have reference of parent id in child table when adding new row to child table.
In Ew_test_reftable class, you have
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
If I understand correctly, testid is your foreign key in EW_TEST_REFTABLE, then why are you using GenerationType.IDENTITY ? This will create new sequence id and may not match with parent key and result in error/exception.
As per my understanding of your design,
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
change to
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_testdata ew_testdata;
And similar to above code should be removed from Ew_testdata entity (There might be slight change here and there)

OneToMany relationship and composite primary keys cascading

I am using JPA (Hibernate) and trying to persist entire new entity with childs and composite keys, but when persisting childs i getting null in key. Table structure:
CREATE TABLE IDENTITY_DOCS
(
PERSON_ID BIGINT NOT NULL,
DOC_TYPE_ID BIGINT NOT NULL,
...
);
CREATE TABLE DOC_TYPES
(
DOC_TYPE_ID BIGINT PRIMARY KEY NOT NULL,
...
);
CREATE TABLE PERSONS
(
PERSON_ID BIGINT PRIMARY KEY NOT NULL,
...
);
Mappings:
#IdClass(...IdentityDocsPK.class)
#Table(name = "IDENTITY_DOCS")
#Entity
public class IdentityDocs {
#Id
#Column(name = "PERSON_ID", nullable = false)
private Long personId;
#Id
#Column(name = "DOC_TYPE_ID")
private Long docTypeId;
#ManyToOne
#MapsId("personId")
#JoinColumn(name = "PERSON_ID", referencedColumnName = "PERSON_ID")
private Employee employee;
...
}
public class IdentityDocsPK implements Serializable {
private Long personId;
private Long docTypeId;
...
}
#Table(name = "PERSONS")
#Entity
#Where(clause = "PERSON_TYPE_ID = 1")
public class Employee {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PERSON_ID")
#Id
private Long personId;
...
#OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private List<IdentityDocs> identityDocs;
}
#Table(name = "DOC_TYPES")
#Entity
public class DocTypes {
#Id
#Column(name = "DOC_TYPE_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long docTypeId;
...
}
Test case:
Employee employee = new Employee();
employee.setFirstName("AAAA");
employee.setLastName("BBBB");
employee.setPersonNumber("1337");
IdentityDocs docs1 = new IdentityDocs();
docs1.setDocTypeId(1L); // already in database
docs1.setDocNumber("11111");
docs1.setDocSeries("11111");
docs1.setPlaceIssue("1111");
employee.setIdentityDocs(new ArrayList<IdentityDocs>());
employee.getIdentityDocs().add(docs1);
em.persist(employee);
Error code:
NULL not allowed for column "PERSON_ID"; SQL statement:
insert into IDENTITY_DOCS (DATE_EXPIRED, DATE_ISSUE, DOC_NUMBER, DOC_SERIES, PLACE_ISSUE, DOC_TYPE_ID, PERSON_ID) values (?, ?, ?, ?, ?, ?, ?)
I also tried without #MapsId (using insertable = false, updatable=false on relevant field), but with same result. Question #OneToMany and composite primary keys? is relevant, but i dont find answer there
Maybe should have an AUTO_INCREMENT clause on your person_id field in your DDL, or generate the key in some other way.

Hibernate #OneToMany without a separate join table

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.

Categories