How to cascade persist using JPA/EclipseLink - mysql

I am having problems performing a cascade persist operation on a parent entity. When the child entity is persisted, the reference (generated id) to the parent entity is null. How would I get this to persist correctly?
Entities:
#Entity
public class Contact {
#Id #GeneratedValue(strategy=GenerationType.TABLE, generator="contact_gen")
#TableGenerator(name="contact_gen",
table="id_gen", pkColumnName="gen_name",
valueColumnName="gen_val", pkColumnValue="cont_gen")
#Column(name="contact_id")
private Long id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="contact", cascade=CascadeType.PERSIST)
private List<Address> addresses = new ArrayList<Address>();
public void addAddress(Address address) {
addresses.add(address);
}
...
}
#Entity
public class Address {
#Id #GeneratedValue(strategy=GenerationType.TABLE, generator="address_gen")
#TableGenerator(name="address_gen",
table="id_gen", pkColumnName="gen_name",
valueColumnName="gen_val", pkColumnValue="addr_gen")
#Column(name="address_id")
private Long id;
#Column(name="full_address")
private String fullAddress;
#ManyToOne
#JoinColumn(name="contact_id")
private Contact contact;
...
}
Service:
#Stateless
public class ContactService {
#PersistenceContext
private EntityManager em;
public void createContact() {
Contact contact = new Contact();
contact.setName("Michael Scott");
contact.addAddress(new Address("1725 Slough Avenue");
em.persist(contact);
}
}
MySQL Tables & Inserts:
CREATE TABLE `contact` (
`contact_id` int(11) NOT NULL,
`name` varchar(45) NOT NULL
PRIMARY KEY (`contact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `address` (
`address_id` int(11) NOT NULL,
`full_address` varchar(100) NOT NULL,
`contact_id` int(11) NOT NULL,
PRIMARY KEY (`address_id`),
KEY `FK_ADDRESS_contact_id` (`contact_id`),
CONSTRAINT `FK_ADDRESS_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `contact` (`contact_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE id_gen (
gen_name VARCHAR(80),
gen_val INT,
PRIMARY KEY (gen_name)
);
INSERT INTO id_gen (gen_name, gen_val) VALUES ('cont_gen', 0);
INSERT INTO id_gen (gen_name, gen_val) VALUES ('addr_gen', 0);

Sadly, you're not showing the content of addAddress. Since your association is bidirectional, are you setting "both sides of the link" in this method? Something like this:
#Entity
public class Contact {
...
#OneToMany(mappedBy="contact", cascade=CascadeType.PERSIST)
private List<Address> addresses = new ArrayList<Address>();
public void addToAddresses(Address address) {
address.setContact(this);
this.addresses.add(address);
}
}

Related

I want to implement foreign key in my Springboot project but I get the following errors

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.Tue Oct 10 17:11:14 IST 2018 There was an unexpected error (type=Internal Server Error, status=500). could not execute statement; SQL [n/a]; nested exception is org.
hibernate.exception.SQLGrammarException: could not execute statement.
STS Error:
Before changing the code
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolation
Exception
: Cannot add or update a child row: a foreign key constraint fails
(workdemo.officeinfo, CONSTRAINT idFOREIGN KEY (id) REFERENCES mytable
(id))
After implementing joincolumn
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.AnnotationException: No identifier
specified for entity:com.infidata.modal.MyTable
POJO( value with getters and setters,also
generated value)
Office.java
package com.infidata.modal;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="officeinfo")
public class Office {
#Id
private int sno;
private String batchno;
#ManyToOne
#JoinColumn(name = "id" )
private MyTable myTable;
private String fees;
private String reciptno;
private String trainer;
public Office() {
}
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public String getBatchno() {
return batchno;
}
public void setBatchno(String batchno) {
this.batchno = batchno;
}
public String getFees() {
return fees;
}
public void setFees(String fees) {
this.fees = fees;
}
public String getReciptno() {
return reciptno;
}
public void setReciptno(String reciptno) {
this.reciptno = reciptno;
}
public String getTrainer() {
return trainer;
}
public void setTrainer(String trainer) {
this.trainer = trainer;
}
public Office(String batchno,String fees, String reciptno,String trainer) {
super();
this.batchno = batchno;
this.fees = fees;
this.reciptno = reciptno;
this.trainer=trainer;
}
#Override
public String toString() {
return "Office [sno=" + sno + ", batchno=" + batchno + ",fees=" + fees
+ ", reciptno=" + reciptno + ",trainer=" + trainer + "]";
}
}
MyTable.java
package com.infidata.modal;
#Entity
public class MyTable {
}
Database(name of database is workdemo)
User table(Table name: mytable)
CREATE TABLE `mytable`
( `id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
`mobile` varchar(10) NOT NULL,
`email` varchar(45) NOT NULL,
`college` varchar(45) NOT NULL,
`branch` varchar(45) NOT NULL,
`semester` varchar(45) NOT NULL,
`address` varchar(105) NOT NULL,
`internship` varchar(45) NOT NULL,
`batch` varchar(45) NOT NULL,
`startdate` varchar(45) NOT NULL,
`enddate` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
Office table(Table name:office)
CREATE TABLE `office`
(`sno` int(11) NOT NULL AUTO_INCREMENT,
`batchno` varchar(45) NOT NULL,
`id` int(11) NOT NULL,
`fees` varchar(45) NOT NULL,
`reciptno` varchar(45) NOT NULL,
PRIMARY KEY (`sno`),
KEY `id_idx` (`id`),
CONSTRAINT `id` FOREIGN KEY (`id`) REFERENCES `mytable` (`id`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
The id(foreign key) in office table should be autoincremented with reference to student id column attribute
The problem is how you defined the entity class :
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
When you use JPA, you must specify the target entity of the relationship, not the field from database.
Your definition just tells the hibernate to generate an int value which will not correspond to a real entity.
It should be something like this:
#ManyToOne
#JoinColumn(name = "id" )
private User user;
Your office object will be
#Entity
#Table(name = "officeinfo")
public class Office {
#Id
private int sno;
private String batchno;
#ManyToOne
#JoinColumn(name = "id")
private User user;
private String fees;
private String reciptno;
private String trainer;
// getters and setters;
}
Please make sure that #Id is only on sno and you don't have on another fields, otherwise it will fail with composite key exception. Please remove id from your object, it is the foreign key to User and it is handled by:
#ManyToOne
#JoinColumn(name = "id")
private User user;

Cakephp $scaffold doesn't display associated models

Help me please, I'm desperate!
I have this schema:
CREATE TABLE `baskets` (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`name` varchar(20)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `apples` (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`basket_id` INT UNSIGNED ,`type` int,
FOREIGN KEY (basket_id) references baskets(id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
These are my models:
class Apple extends AppModel {
public $name = 'Apple';
public $recursive = 2;
public $belongsTo = 'Basket';
}
class Basket extends AppModel {
public $name = 'Basket';
public $recursive = 2;
public $hasMany = 'Apple';
}
However, when I call the variable $scaffold on either one of them, and try to update or create a new apple; the little drop-down thingy where I would normally choose a basket is empty.
What can I do???? I'm gonna get fired if I don't solve this by monday :(

JPA with Hibernate issue when persisting Entities with one-one relationship between them

I have two tables - bill & billSimpleentry and two corresponding Entity classes Bill & BillSimpleEntry.
Bill and BillSimpleentry have a one-one relationship. Each bill has one billsimpleentry. So billsimplementry.billId has the same corresponding value of bill.id.
SQL structure:
CREATE TABLE `bill` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(100) DEFAULT NULL,
.....
.....
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
KEY `fk_bill_groups1_idx` (`groupId`),
KEY `fk_bill_user1_idx` (`billPayerId`),
CONSTRAINT `fk_bill_groups` FOREIGN KEY (`groupId`) REFERENCES `groups` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_bill_user` FOREIGN KEY (`billPayerId`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = #saved_cs_client */;
CREATE TABLE `billsimpleentry` (
`itemTitle` varchar(200) DEFAULT NULL,
`itemDescription` text,
`billId` bigint(20) NOT NULL,
PRIMARY KEY (`billId`),
KEY `fk_bill_idx` (`billId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = #saved_cs_client */;
So when a new 'bill' object is persisted, it should also create a billsimpleentry row in the database.
save(Bill newBill){
em.persist(newBill);
}
Bill class structure:
#Entity
#Table(name = "bill")
public class Bill implements GenericObject {
private static final long serialVersionUID = -5660869020353250221L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
....
private Long groupId;
private BigDecimal billTotal;
#OneToOne(cascade=CascadeType.ALL,fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn
private BillSimpleEntry billSimpleEntry;
... getters & setters...
}
BillSimpleEntry:
#Entity
#Table(name="billsimpleentry")
public class BillSimpleEntry implements GenericObject{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long billId;
#Column(columnDefinition="TEXT")
private String itemDescription;
#OneToMany(cascade=CascadeType.ALL,mappedBy="billSimpleEntryId",fetch = FetchType.EAGER)
private List<SimpleUserIdAndLiableCost> simpleUserIdAndLiableCost = new ArrayList<SimpleUserIdAndLiableCost>();
... getters & setters...
}
Here is the newBill obj data that is attempted to be persisted
{
"id":null,
"title":"",
"billDate":null,
"billPayerId":6,
"notes":null,
"billCreaterId":null,
"groupId":3,
"billTotal":null,
"billSimpleEntry":{
"billId":null,
"itemDescription":null,
"simpleUserIdAndLiableCost":[
{
"userId":6,
"liableCost":"50",
"id":null,
"billSimpleEntryId":null,
"user":{
"id":null,
"fName":"doe",
"lName":"doe"
},
"isActive":true
},
{
"userId":7,
"liableCost":"50",
"id":null,
"billSimpleEntryId":null,
"user":{
"id":null,
"fName":"doe",
"lName":"doe"
},
"isActive":true
},
{
"userId":8,
"liableCost":"50",
"id":null,
"billSimpleEntryId":null,
"user":{
"id":null,
"fName":"doe",
"lName":"doe"
},
"isActive":true
}
],
"itemDescriptionId":2
},
"billItemEntry":[
],
"userId":null
}
But the problem is that em.persist(Bill) fails because billsimpleentry.billId value needs to be populated to the same value as of bill.id. How should I fix this problem? It appears like I need to update my table structure or the table auto id generation strategy. Any insights would be appreciated.
Sorry, but I need more clarification. I don't know how you create that JSON, but in them is this "billId":null. You need to set the parent ID. So, if that is JSON, process it before persist and attach parent ID to it. Save or persist should not attach parent id to childs automatically.

How do I Code one entity into another?

This is what my SQL tables look like:
CREATE TABLE IF NOT EXISTS `test`.`Families` (
`id` INT NOT NULL AUTO_INCREMENT,
`mother_id` INT DEFAULT NULL ,
`father_id` INT DEFAULT NULL ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `test`.`Parents` (
`id` INT NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(50) DEFAULT NULL,
`last_name` VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
And this is what my family entity looks like:
#Entity
#Table(name="Families")
public class Family implements Serializable {
#Id
#Column(name="id")
private String id;
#Column(name="mother_id")
private int mother;
#Column(name="father_id")
private int father;
}
Which is great and all, but I would really LOVE if I could do something like this (note I also have a Parent entity already defined):
#Entity
#Table(name="Families")
public class Family implements Serializable {
#Id
#Column(name="id")
private String id;
#OneToOne
#Column(name="mother_id")
private Parent mother;
#OneToOne
#Column(name="father_id")
private Parent father;
}
How could I go about making this happen?
Actually, Hibernate does everything for you.
You don't need to annotate columns with #Column which already have #OneToOne or other association annotations
If you want to use other than default foreign key(by default name consists of field + _id), you should use #JoinColumn annotation
#Entity
#Table(name="Families")
public class Family implements Serializable {
#Id
#Column(name="id")
private String id;
#OneToOne
#JoinColumn(name = "mother_idd")
private Parent mother;
#OneToOne
#JoinColumn(name = "father_idd")
private Parent father;
}

Hibernate fails in fetching collections

I've got an issue with Hibernate. What I have to do is to retrieve a collection of Team when I select a Deliverable. Here's the Deliverable class:
#Entity(name="Deliverable")
{"MilestoneID", "TeamID"})})
#Table(name="Deliverable")
public class Deliverable implements Serializable, Comparable<Deliverable> {
private static final long serialVersionUID = 2138806103760654922L;
#Id
#Column(name="DeliverableID", nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
private int deliverableID;
#ManyToOne(optional=false)
#JoinColumn(name="MilestoneID", nullable=false)
private Milestone milestone;
#ManyToOne(optional=false)
#JoinColumn(name="TeamID", nullable=false)
private Team team;
#Column(name="Score", nullable=false)
private int score;
#OneToMany(mappedBy="deliverable")
private Set<Version> versions;
#OneToMany(mappedBy="visibleDeliverables")
private Collection<Team> viewers;
I haven't copied getters and setters for space reasons. This is the query I want to execute:
#NamedQuery(
name="Deliverable.getDeliverableById",
query="SELECT d FROM Deliverable AS d LEFT JOIN FETCH d.viewers AS v WHERE d.deliverableID = :id"
)
And here's the exception I get:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'viewers1_.DeliverableID' in 'field list'
It's getting frustrating =(
EDIT: here's the sql to create the Deliverable table
CREATE TABLE IF NOT EXISTS `Deliverable` (
`DeliverableID` INT NOT NULL AUTO_INCREMENT ,
`MilestoneID` INT NOT NULL ,
`TeamID` INT NOT NULL ,
`Score` INT NOT NULL DEFAULT 1 ,
PRIMARY KEY (`DeliverableID`) ,
INDEX `fk_Delivarable_Milestone` (`MilestoneID` ASC) ,
INDEX `fk_Delivarable_Team` (`TeamID` ASC) ,
UNIQUE INDEX `MilestoneID_TeamID_UNIQUE` (`MilestoneID` ASC, `TeamID` ASC) ,
CONSTRAINT `fk_Delivarable_Milestone`
FOREIGN KEY (`MilestoneID` )
REFERENCES `Milestone` (`MilestoneID` )
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_Delivarable_Team`
FOREIGN KEY (`TeamID` )
REFERENCES `Team` (`TeamID` )
ON DELETE CASCADE
ON UPDATE CASCADE)
EDIT: and here's the Team entity
public class Team implements Serializable {
private static final long serialVersionUID = -6434099499828214268L;
#Id
#Column(name="TeamID", nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
private int teamID;
#ManyToOne(optional=false)
#JoinColumn(name="ProjectID", nullable=false)
private Project project;
#ManyToOne(optional=false)
#JoinColumn(name="Founder", nullable=false)
private Student founder;
#Column(name="Name", nullable=false, length=100)
private String name;
#ManyToMany
#JoinTable(name="Student_Invite", joinColumns={#JoinColumn(name="TeamID")},
inverseJoinColumns={#JoinColumn(name="StudentID")})
private Set<Student> invitedStudents = new HashSet<Student>();
#ManyToMany
#JoinTable(name="Student_Member", joinColumns={#JoinColumn(name="TeamID")},
inverseJoinColumns={#JoinColumn(name="StudentID")})
private Set<Student> members = new HashSet<Student>();
#ManyToMany
#JoinTable(name="Deliverable_View", joinColumns={#JoinColumn(name="ViewerTeamID")},
inverseJoinColumns={#JoinColumn(name="DeliverableID")})
private Set<Deliverable> visibleDeliverables = new HashSet<Deliverable>();
#OneToMany(mappedBy="team")
private Set<Deliverable> deliverables = new HashSet<Deliverable>();
#Column(name="Frozen", nullable=false)
private boolean frozen;
EDIT: Deliverable_View
CREATE TABLE IF NOT EXISTS `Deliverable_View` (
`ViewerTeamID` INT NOT NULL ,
`ViewedTeamID` INT NOT NULL ,
`DeliverableID` INT NOT NULL ,
PRIMARY KEY (`ViewerTeamID`, `ViewedTeamID`, `DeliverableID`) ,
INDEX `fk_ViewerTeamID` (`ViewerTeamID` ASC) ,
INDEX `fk_ViewedTeamID` (`ViewedTeamID` ASC) ,
INDEX `fk_DeliverableView_Delivarable` (`DeliverableID` ASC) ,
CONSTRAINT `fk_ViewerTeamID`
FOREIGN KEY (`ViewerTeamID` )
REFERENCES `Team` (`TeamID` )
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_ViewedTeamID`
FOREIGN KEY (`ViewedTeamID` )
REFERENCES `Team` (`TeamID` )
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_DeliverableView_Delivarable1`
FOREIGN KEY (`DeliverableID` )
REFERENCES `Deliverable` (`DeliverableID` )
ON DELETE CASCADE
ON UPDATE CASCADE)