Mapping Relation in spring data jpa - spring-boot

I have created SQL tables to achieve mapping relations It works for all my requirements same thing not able to achieve in spring boot and spring data JPA. My use cases are
Add Company with User
Associate a user for a company
Update user & company
Fetch company and its associated users
Fetch User and his associated companies
CREATE TABLE `Company` (
`CompanyID` bigint NOT NULL AUTO_INCREMENT,
`CompanyName` varchar(255) DEFAULT NULL,
`CompanyDescription` varchar(255) DEFAULT NULL,
`CompanyWebsite` varchar(255) DEFAULT NULL,
`CompanyDomain` varchar(255) DEFAULT NULL,
`CompanyTypeID` int DEFAULT NULL,
`NumberOfEmployeesID` int NOT NULL,
`CompanyLogo` longtext,
`CompanyStatus` int NOT NULL,
`Active` bit(1) NOT NULL,
`CompanyAddressID` bigint NOT NULL,
`CreatedBy` bigint NOT NULL,
`CreatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` bigint DEFAULT NULL,
`UpdatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`CompanyID`),
KEY `FK_COMPANY_ADDRESS_ID` (`CompanyAddressID`),
CONSTRAINT `FK_COMPANY_ADDRESS_ID` FOREIGN KEY (`CompanyAddressID`) REFERENCES `CompanyAddress` (`CompanyAddressID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `CompanyAddress` (
`CompanyAddressID` bigint NOT NULL AUTO_INCREMENT,
`Street` varchar(255) DEFAULT NULL,
`CountryID` int NOT NULL,
`StateID` int NOT NULL,
`CityID` int NOT NULL,
`ZipCode` int NOT NULL,
`PhoneCountryID` int NOT NULL,
`Phone` bigint NOT NULL,
`PhoneExternsion` int NOT NULL,
`CreatedBy` bigint NOT NULL,
`CreatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` bigint DEFAULT NULL,
`UpdatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`CompanyAddressID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `User` (
`UserID` bigint NOT NULL AUTO_INCREMENT,
`FirstName` varchar(255) DEFAULT NULL,
`LastName` varchar(255) DEFAULT NULL,
`Email` varchar(255) DEFAULT NULL,
`EncryptedEmail` varchar(255) DEFAULT NULL,
`UserName` varchar(255) DEFAULT NULL,
`Password` varchar(255) DEFAULT NULL,
`UserStatus` varchar(255) DEFAULT NULL,
`GUID` varchar(255) DEFAULT NULL,
`IsNotLocked` bit(1) NOT NULL DEFAULT b'1',
`LastLogin` datetime(6) DEFAULT NULL,
`ProfilePicture` longtext,
`UserAddressID` bigint NOT NULL,
`CreatedBy` bigint NOT NULL,
`CreatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` bigint DEFAULT NULL,
`UpdatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`UserID`),
KEY `FK_USER_ADDRESS_ID` (`UserAddressID`),
CONSTRAINT `FK_USER_ADDRESS_ID` FOREIGN KEY (`UserAddressID`) REFERENCES `UserAddress` (`UserAddressID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `UserAddress` (
`UserAddressID` bigint NOT NULL AUTO_INCREMENT,
`Street` varchar(255) DEFAULT NULL,
`CountryID` int DEFAULT NULL,
`StateID` int DEFAULT NULL,
`CityID` int DEFAULT NULL,
`ZipCode` int DEFAULT NULL,
`PhoneCountryID` int NOT NULL,
`Phone` bigint NOT NULL,
`LandPhoneCountryID` int DEFAULT NULL,
`LandPhone` bigint DEFAULT NULL,
`LandPhoneExternsion` int DEFAULT NULL,
`CreatedBy` bigint NOT NULL,
`CreatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` bigint DEFAULT NULL,
`UpdatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`UserAddressID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `CompanyUserMapping` (
`MappingID` bigint NOT NULL AUTO_INCREMENT,
`UserID` bigint NOT NULL,
`CompanyID` bigint NOT NULL,
`UserTitle` varchar(255) NOT NULL,
`Role` varchar(255) NOT NULL,
`Authorities` varchar(255) NOT NULL,
`CustomerID` bigint NOT NULL,
`External` bit(1) NOT NULL,
`Active` bit(1) NOT NULL,
`CreatedBy` bigint NOT NULL,
`CreatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` bigint DEFAULT NULL,
`UpdatedTS` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`MappingID`),
KEY `FK_CompanyUserMapping_COMPANY_ID` (`CompanyID`),
KEY `FK_CompanyUserMapping_User_ID` (`UserID`),
CONSTRAINT `FK_CompanyUserMapping_COMPANY_ID` FOREIGN KEY (`CompanyID`) REFERENCES `Company` (`CompanyID`),
CONSTRAINT `FK_CompanyUserMapping_User_ID` FOREIGN KEY (`UserID`) REFERENCES `User` (`UserID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
My model classes
#Getter
#Setter
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
private String firstName;
private String lastName;
private String email;
private String encryptedEmail;
private String username;
private String password;
private String userStatus;
private String guid;
private Boolean isNotlocked;
private Date lastLogin;
private String profilePic;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "address_id")
private UserAddress address;
#OneToMany(mappedBy = "user")
#JsonBackReference
Set<CompanyUserMapping> companyUserMapping;
}
#Getter
#Setter
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long companyId;
private String companyName;
private String companyDescription;
private String companyWebsite;
private String companyEmailDomain;
private Integer companyTypeID;
private Integer numberOfEmployeesID;
private String companyLogo;
private Integer companyStatus;
private Boolean active;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "address_id")
private CompanyAddress address;
#OneToMany(mappedBy = "company")
#JsonBackReference
Set<CompanyUserMapping> companyUserMapping;
}
#Getter
#Setter
#Entity
public class CompanyUserMapping {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long companyUserMappingId;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "company_id")
private Company company;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
private String role;
private String [] authorities;
private boolean isExternal;
private boolean isActive;
private Long customerId;
}
Problems
When I do Fetch company and its associated users are not able to get into the below Hierarchy and also not able to get the address of them
{
"companyId": 1,
"companyName": "ABC",
"address": {},
"users": [{
"userId": 1,
"email": "sachin#gmail.com",
"address": {}
}]
}
Eror
[
{
"companyUserMappingId": 1,
"company": {
"companyId": 1,
"companyName": "abc",
"companyDescription": "xxxxx",
"companyWebsite": "xxxxxxxxx",
"companyEmailDomain": "xxxxx",
"companyTypeID": 1,
"numberOfEmployeesID": 1,
"companyLogo": "Logo data",
"companyStatus": 3,
"active": true,
"address": {
"addressId": 1,
"street": "Shanthappa",
"countryId": 1,
"stateID": 1,
"cityID": 1,
"zipCode": 1234,
"phoneCountryID": 1,
"phone": 316986,
"phoneExtension": 3654
}
}
}
]{
"timestamp": "2022-06-06T09:27:07.487+00:00",
"message": "Type definition error: [simple type, class com.pradeep.domain.CompanyAddress]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: java.util.ArrayList[0]->com.pradeep.domain.CompanyUserMapping[\"company\"]->com.pradeep.domain.Company[\"address\"]->com.pradeep.domain.CompanyAddress[\"address\"])",
"path": "uri=/api/company/1",
"application": "DBLayer"
}

Related

Spring Data JPA + Postgres - Unable to insert data with One to One mapping

I have a UserInfo and AddressInfo entity classes and they have one to one association. UserInfo uses sequence to add primary key but I am getting below error;
org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property
UserInfo Entity
#Entity
#Table(name = "userinfo")
public class UserInfo {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "userid_seq")
#SequenceGenerator(name="userid_seq", allocationSize=1)
private Long userId;
private String firstName;
private String lastName;
private String email;
private String username;
private String password;
#OneToOne(mappedBy = "userInfo", cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private AddressInfo addressInfo;
//Getters - Setters
}
AddressInfo Entity
#Entity
#Table(name = "addressinfo")
public class AddressInfo {
#Id
private Long addressId;
private String homeAddress;
private String homeCity;
private String homeState;
private String homeZip;
#OneToOne
#MapsId
#JoinColumn(name = "address_id")
private UserInfo userInfo;
//Getters - Setters
}
UserInfo Table
CREATE TABLE userinfo (
user_id INTEGER NOT NULL DEFAULT nextval('userid_seq') PRIMARY KEY ,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
username VARCHAR(20) NOT NULL,
password VARCHAR(20) NOT NULL
);
AddressInfo Table
CREATE TABLE addressinfo (
address_id INTEGER NOT NULL PRIMARY KEY,
home_address VARCHAR(100) NULL,
home_city VARCHAR(100) NULL,
home_state VARCHAR(100) NULL,
home_zip VARCHAR(100) NULL,
CONSTRAINT fk_addinfo
FOREIGN KEY(address_id)
REFERENCES userinfo(user_id)
);
I thought my sequence had some issues but I could see that if I remove the child entity then its is inserting into the UserInfo table successfully but getting above error when I add OneToOne mapping. Seems like I have issues with my Primary key. I see similar questions but I could not find what is going on here. A help would be really appreciated.
Two solutions come to mind:
A single transaction that inserts both Userinfo and Addressinfo. With the second insert using the sequence currval to define the id.
create table addressinfo (
address_id integer default currval('userid_seq') primary key,
home_address varchar(100) null,
home_city varchar(100) null,
home_state varchar(100) null,
home_zip varchar(100) null,
constraint fk_addinfo
foreign key(address_id)
references userinfo(user_id)
);
do $$
begin
insert into userinfo (first_name, last_name, email, username, password)
values ('Jane','Smith','j.smith#thisplace.org','js','psojHvIEJNB');
insert into addressinfo( home_address, home_city, home_state,home_zip)
values ('1 Joe''s Lane','Smithtown', 'NV', '0123456789asdfgh');
end;
$$;
A single statement handling the insert for both tables:
with newuser (user_id) as
(insert into userinfo (first_name, last_name, email, username, password)
values ('Joe','Smith','j.s.smith#thisplace.org','js2','+949+fsrgwDGKJS58')
returning user_id
) --select id from newuser;
insert into addressinfo(address_id, home_address, home_city, home_state,home_zip)
select user_id,'1 Joe''s Lane','Smithtown', 'NV', '0123456789asdfgh'
from newuser;
However neither is a good plan. A 1:1 relationships are always questionable. In this case they are not. What happens when user Jane Smith stores her address, then insists that her husband, Joe, have the same address. You wind up with DUPLICATE addresses. See example here. You might be better off giving addressinfo its own PK sequence and putting address_id as a column and FK into userinfo

how to fix incompatible foreign key constraints spring boot

I have a spring boot application where I have two entities in a relationship. MeetingsSetting and meetingTime. One MeetingSetting can have multiple meetingTimes and one meetingtime belongs to one Meetingsetting.
I generate the databases through sql script and reference the foreing key their for the meetingTime entity. But I am getting the following error:
Caused by: java.sql.SQLException: Referencing column 'meeting_name' and referenced column 'id' in foreign key constraint 'FK1omm6fk51xdsd0kysqbmleweg' are incompatible.
THe funny thing is I am not referencing the id anywhere not in my entity nor in my script. This is how my entity and script looks like:
meetingSetting:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name")
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meeting_Name", cascade = CascadeType.ALL)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
MeetingTime:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#Column(name = "meeting_name",insertable = false, updatable = false )
private String meetingName;
#ManyToOne
#JoinColumn(name = "meeting_name", nullable = false)
private MeetingsSetting meeting_Name;
}
and this is my script where I generate my tables:
-- auto-generated definition
create table meeting_settings
(
id bigint auto_increment
primary key,
meeting_name varchar(255) null,
meeting_pw varchar(255) null,
meeting_url varchar(255) null
);
create table meeting_times
(
id bigint auto_increment
primary key,
meeting_date varchar(255) null,
start_time varchar(255) null,
end_time varchar(255) null,
meeting_name varchar(255) null,
constraint fk_meeting_times_meeting_name
foreign key (meeting_name) references meeting_settings (meeting_name)
);
What could cause such an error? because I am not referencing anywhere the id.
UPDATE:
spring.datasource.url=jdbc:mysql://localhost:3306/coorporate_blinddate?createDatabaseIfNotExist=true&useSSL=true&serverTimezone=UTC
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=../generate.sql
spring.jpa.show-sql= true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto = update
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=Test1234##1&
server.port=8081
Hibernate Sequence:
Hibernate: create table meeting_settings (id bigint not null auto_increment, meeting_name varchar(255), meeting_pw varchar(255), meeting_url varchar(255), primary key (id)) engine=InnoDB
Hibernate: create table meeting_settings_meeting_time (meetings_setting_id bigint not null, meeting_name bigint not null, primary key (meetings_setting_id, meeting_name)) engine=InnoDB
Hibernate: create table meeting_times (id bigint not null auto_increment, meeting_date varchar(255), end_time varchar(255), meeting_name varchar(255), start_time varchar(255), primary key (id)) engine=InnoDB
Hibernate: alter table meeting_settings drop index UK_klg4vqmhi7o9qff83ymly598o
Hibernate: alter table meeting_settings add constraint UK_klg4vqmhi7o9qff83ymly598o unique (meeting_name)
Hibernate: alter table meeting_settings_meeting_time drop index UK_jsn83wsxfkpm1xfencvsdkqj1
Hibernate: alter table meeting_settings_meeting_time add constraint UK_jsn83wsxfkpm1xfencvsdkqj1 unique (meeting_name)
Hibernate: alter table meeting_settings_meeting_time add constraint FK9lq62drkkslq6x381b3lieruu foreign key (meeting_name) references meeting_times (id)
Hibernate: alter table meeting_settings_meeting_time add constraint FKglhgb5vgsviqm7t6vtmdx5e7t foreign key (meetings_setting_id) references meeting_settings (id)
Hibernate: alter table meeting_times add constraint FK1omm6fk51xdsd0kysqbmleweg foreign key (meeting_name) references meeting_settings (id)
A table which is generated
meeting_settings_meeting_time
meetings_setting_id
meeting_name
PRIMARY
UK_jsn83wsxfkpm1xfencvsdkqj1
FK9lq62drkkslq6x381b3lieruu
FKglhgb5vgsviqm7t6vtmdx5e7t
UK_jsn83wsxfkpm1xfencvsdkqj1
Looks like your meeting_name column is not unique in order to do the relationship you have done. Add unique = true
#Column(name = "meeting_name", unique = true)
private String meetingName;
And
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(inverseJoinColumns=#JoinColumn(name="meeting_name"))
private Set<MeetingTime> meetingTime = new HashSet<>();

Spring Boot JPA One To Many and Many to One With Multiple Tables

I have 5 Tables, A User can have many module/role/plant. user_master is the main table with user details and user_roles is the sub table with module/role/plant details. My doubt is how to write the relationship in Model Class.
user_master
------------
user_id int(10) unsigned
first_name varchar(50)
last_name varchar(50)
mail_id varchar(80)
user_status tinyint(4)
is_deleted tinyint(4)
created_by int(10)
created_date date
modified_by int(10)
modified_date date
user_roles
-----------
user_role_id int(10) unsigned
user_id int(10) unsigned
module_master_id int(10) unsigned
role_master_id int(10) unsigned
plant_master_id int(10) unsigned
module_master:
module_master_id int(10) unsigned
module_code int(10)
module_name varchar(50)
active_flag tinyint(4)
role_master:
role_master_id int(10) unsigned
module_master_id int(10) unsigned
role_code int(10)
role_name varchar(50)
active_flag tinyint(4)
plant_master:
plant_master_id int(10) unsigned
plant_code int(10)
plant_name varchar(50)
active_flag tinyint(4)
The remaining module/role/plant have their own masters, master_id are primary key to master tables.
I just want to write user_master and user_roles model class. One-to-many & many-to-one mapping is required.
For one to many, you can have like below in your entity class:
#OneToMany in user entity
#OneToMany(mappedBy = "user")
private List<Role> roles;
#ManyToOne at roles side
#ManyToOne
#JoinColumn(name = "user")
private User user;
#ManyToMany
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "user_role",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private List<Role> roles= new ArrayList<>();
and role side:
#ManyToMany(mappedBy = "role")
private List<User> users = new ArrayList<>();
here is an example to have many to many with emdeded:
#Entity
public class UserRoleMaster implements Serializable {
#EmbeddedId
private UserRoleMasterId id;
#ManyToOne
#JoinColumn(name = "user_master_id", referencedColumnName = "user_master_id", insertable = false, updatable = false)
private UserMaster userMaster;
#ManyToOne
#JoinColumn(name = "user_roles_id", referencedColumnName = "user_roles_id", insertable = false, updatable = false)
private UserRoles userRoles;
//getter //setter //constructures
#Embeddable
public static class UserRoleMasterId implements Serializable {
#Column(name = "user_master_id")
protected Long userMasterId;
#Column(name = "user_roles_id")
protected Long userRolesId;
//constrcture //getter //setters
}
}

how to use bidirectional many to many mapping following error is thrown Cannot add or update a child row: a foreign key constraint fails

I am trying to implement the birectional many to many mapping (question,tags,question_tag) by using the following tables using Spring & Hibernate
TABLE user:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NOT NULL,
`password` varchar(255) DEFAULT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
TABLE question:
CREATE TABLE `question` (
`qid` int(11) NOT NULL AUTO_INCREMENT,
`questiontitle` varchar(255) DEFAULT NULL,
`questionbody` varchar(3000) DEFAULT NULL,
`uid` int(11) NOT NULL,
`votes` int(11) NOT NULL,
`created_on` DATETIME NOT NULL DEFAULT NOW(), -- or CURRENT_TIMESTAMP
PRIMARY KEY (`qid`),
CONSTRAINT `fk_user_id` FOREIGN KEY (`uid`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
TABLE tags:
CREATE TABLE `tags` (
`tagid` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) DEFAULT NULL,
PRIMARY KEY (`tagid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
TABLE question_tag:
CREATE TABLE `question_tag` (
`qid` int(11) NOT NULL,
`tagid` int(11) NOT NULL,
PRIMARY KEY (`qid`,`tagid`),
CONSTRAINT `fk_qt_qid` FOREIGN KEY (`qid`) REFERENCES `question` (`qid`),
CONSTRAINT `fk_tags_tagid` FOREIGN KEY (`tagid`) REFERENCES `tags` (`tagid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Model used are
Question.Java
#Entity
#Table(name="question")
#NamedQuery(name="Question.findAll", query="SELECT q FROM Question q")
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int qid;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="created_on")
private Date createdOn;
private String questionbody;
private String questiontitle;
private int uid;
private int votes;
//bi-directional many-to-one association to Answer
#OneToMany(mappedBy="question")
private Set<Answer> answers = new HashSet<>();
//bi-directional many-to-one association to QuestionComment
#OneToMany(mappedBy="question")
private Set<QuestionComment> questionComments = new HashSet<>();
//bi-directional many-to-many association to Tag
#ManyToMany(targetEntity = Tag.class,cascade = { CascadeType.ALL })
#JoinTable(name = "question_tag",
joinColumns = { #JoinColumn(name = "qid") },
inverseJoinColumns = { #JoinColumn(name = "tagid") })
private Set<Tag> tags;
//bi-directional many-to-one association to UserQuestionUpvote
#OneToMany(mappedBy="question")
private Set<UserQuestionUpvote> userQuestionUpvotes = new HashSet<>();
public Question() {
}
}
Tag.Java
#Entity
#Table(name="tags")
#NamedQuery(name="Tag.findAll", query="SELECT t FROM Tag t")
public class Tag implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int tagid;
private String tag;
//bi-directional many-to-many association to Question
#ManyToMany(mappedBy = "tags")
private Set<Question> questions ;
public Tag() {
}
}
There is a questionServiceImpl class which call the questionRepository.save method.
#Service
public class QuestionServiceImpl implements QuestionService {
#Autowired
private QuestionRepository questionRepository;
#Override
public void save(Question question) {
// TODO Auto-generated method stub
questionRepository.save(question);
}
}
Now in the controller when the call to QuestionServiceImpl.save is made insert call to the tables question, tags & question_tag is made but Cannot add or update a child row error is thrown
Hibernate: insert into question (created_on, questionbody, questiontitle, uid, votes) values (?, ?, ?, ?, ?)
Hibernate: insert into tags (tag, tagid) values (?, ?)
Hibernate: insert into question_tag (qid, tagid) values (?, ?)
17:43:36.692 [http-bio-9191-exec-5] ERROR o.h.e.j.s.SqlExceptionHelper#129 Cannot add or update a child row: a foreign key constraint fails (`Forum`.`question_tag`, CONSTRAINT `fk_tags_tagid` FOREIGN KEY (`tagid`) REFERENCES `tags` (`tagid`))
Jul 10, 2018 5:43:36 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`Forum`.`question_tag`, CONSTRAINT `fk_tags_tagid` FOREIGN KEY (`tagid`) REFERENCES `tags` (`tagid`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:400)
at com.mysql.jdbc.Util.getInstance(Util.java:383)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:973)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3847)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3783)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2447)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2594)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1901)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2113)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2049)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2034)

extra NULL item in spring-jpa one-to-many list attribute

spring-jpa with hibernate and mysql 5.7 (dependency managed by spring platform-bom-1.1.4.RELEASE)
Entity class:
#Entity
#Table(name = "activity")
public class ActivityEntity
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
// optional
#Column(name="project_id")
private Integer projectId;
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name="container_id")
private ActivityEntity container;
#OneToMany(mappedBy="container", cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
#OrderColumn(name="order")
private List<ActivityEntity> activities;
private String name;
private String description;
...
}
DAO class:
public interface IActivityDao extends JpaRepository<ActivityEntity, Integer>
{
List<ActivityEntity> findByContainerId(int containerId);
}
Database table:
CREATE TABLE `activity` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`project_id` bigint(20) DEFAULT NULL,
`container_id` bigint(20) DEFAULT NULL,
`name` varchar(128) NOT NULL,
`description` varchar(256) DEFAULT NULL,
`type` varchar(32) NOT NULL,
`mode` varchar(32) NOT NULL,
`tag` varchar(32) DEFAULT NULL,
`script` longtext,
`order` int(11) DEFAULT '1',
`created_user_id` varchar(45) DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`updated_user_id` varchar(45) DEFAULT NULL,
`updated_date` datetime DEFAULT NULL,
`projectId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `container_id` (`container_id`),
CONSTRAINT `fk_container_id` FOREIGN KEY (`container_id`) REFERENCES `activity` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=214 DEFAULT CHARSET=utf8;
Database table content:
Unit Test Code:
public class ActivityDaoTest extends AbstractDaoTest
{
#Resource
private IActivityDao activityDao;
#Test
public void testFindOne() throws Exception {
ActivityEntity activity = activityDao.findOne(210);
ActivityEntity root = activity.getContainer();
int level = 0;
printActivity(activity, level);
Assert.assertNotNull(activity);
if (root != null) {
level = 0;
printActivity(root, level);
}
}
...
}
In the above test code, root.getActivities() and activity.getActivities() return 5 and 4 items respectively, with the first item to be null.
Do I miss something in the entity? Thanks for help.
I'll answer my won question (posted too early):
Remove the order attribute from the Entity
The value of the order column in the table starts from 0 (the NULL item is for the index of 0 in the list)
That solves my problem.

Resources