JPA insert parent and child entities in the same transaction - mysql

I'm completely stuck in this matter, maybe someone can help.
I have two entities, Parent and Child. Test1Entity is the parent, Test1ChildEntity is the child. Great naming, of course. The database is Mysql, the JPA provider is Hibernate. Below are the definitions for the two entities:
#Table(name = "Test1", schema = "", catalog = "")
#Entity
public class Test1Entity {
private int id;
#Column(name = "id")
#Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
private String name;
#Column(name = "name")
#Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test1Entity that = (Test1Entity) o;
if (id != that.id) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
private Collection<Test1ChildEntity> test1ChildrenById;
#OneToMany(mappedBy = "test1ByParentId")
public Collection<Test1ChildEntity> getTest1ChildrenById() {
return test1ChildrenById;
}
public void setTest1ChildrenById(Collection<Test1ChildEntity> test1ChildrenById) {
this.test1ChildrenById = test1ChildrenById;
}
}
#Table(name = "Test1_Child", schema = "", catalog = "")
#Entity
public class Test1ChildEntity {
private int id;
#Column(name = "id")
#Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
private String name;
#Column(name = "name")
#Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test1ChildEntity that = (Test1ChildEntity) o;
if (id != that.id) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
private Test1Entity test1ByParentId;
#ManyToOne
#JoinColumn(name = "parent_id")
public Test1Entity getTest1ByParentId() {
return test1ByParentId;
}
public void setTest1ByParentId(Test1Entity test1ByParentId) {
this.test1ByParentId = test1ByParentId;
}
}
The code trying to insert one parent with one child in the same transaction is below:
#Transactional
public void createItWell(String parentName, String childName) {
Test1Entity parent = new Test1Entity();
parent.setName(parentName);
Test1ChildEntity child = new Test1ChildEntity();
child.setName(childName);
child.setTest1ByParentId(parent);
Set<Test1ChildEntity> mySet = new HashSet<>();
mySet.add(child);
parent.setTest1ChildrenById(mySet);
this.entityManager.persist(parent);
this.entityManager.persist(child);
}
I get the following exception while trying to execute this code:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`comwork`.`test1_child`, CONSTRAINT `test1_child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `Test1` (`id`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4187)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4119)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
Inserting other entities, stand-alone (no relations involved) works perfectly fine.
The two table definitions are:
CREATE TABLE `Test1` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
LOCK TABLES `Test1` WRITE;
/*!40000 ALTER TABLE `Test1` DISABLE KEYS */;
INSERT INTO `Test1` (`id`, `name`)
VALUES
(6,'Parent');
/*!40000 ALTER TABLE `Test1` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table Test1_Child
# ------------------------------------------------------------
CREATE TABLE `Test1_Child` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) unsigned NOT NULL,
`name` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`),
CONSTRAINT `test1_child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `Test1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I'm new to JPA, so sorry for what probably is a trivial question.
Thank you.

Try setting Cascade attribute on OneToMany relation:
#OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
private Collection<Test1ChildEntity> test1ChildrenById;

For whoever runs into this... The entity code was generated using Idea Intellij persistance generating tool.
Apparently the tool fails to annotate the #Id fields with #GeneratedValue, thus disabling id fetching after the first (parent) entity is inserted. This way the child entity was getting inserted with a 0 (obviously invalid) value for the foreign key field.
Just add the #GeneratedValue to the #Id annotated property and it works fine.

Related

Problem with relational tables MySQL. Spring Boot + Hibernate

I'm trying to make relational tables with MySQL and Hibernate.
And here is the code in IntelliJ:
DeviceEntity
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.*;
#Entity
#Table(name = "device")
public class DeviceEntity implements Serializable {
private static final long serialVersionUID = 1L;
// -- Attributes -- //
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "type")
private String type;
#Column(name = "model")
private String model;
#Column(name = "enabled")
private Boolean enabled;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd/MM/yyyy hh:mm:ss")
#Column(name = "created_at")
private Date createdAt;
#OneToMany(fetch = FetchType.LAZY)
private List<PetitionEntity> listPetitionEntity;
// -- Contructors -- //
public DeviceEntity(){
listPetitionEntity = new ArrayList<>();
}
// -- Methods -- //
#PrePersist
public void prePersist() {
createdAt = new Date();
}
// -- Getters & Setters -- //
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public List<PetitionEntity> getListPetitionEntity() {
return listPetitionEntity;
}
public void setListPetitionEntity(List<PetitionEntity> listPetitionEntity) {
this.listPetitionEntity = listPetitionEntity;
}
}
UserEntity
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;
#Entity
#Table(name = "user")
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1L;
// -- Attributes -- //
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "uername")
private String user;
#Column(name = "password")
private String pass;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Column(name = "enabled")
private Boolean enabled;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd/MM/yyyy hh:mm:ss")
#Column(name = "created_at")
private Date createdAt;
#OneToMany(fetch = FetchType.LAZY)
private List<PetitionEntity> listPetitionEntity;
// -- Contructors -- //
public UserEntity() {
listPetitionEntity = new ArrayList<>();
}
// -- Methods -- //
#PrePersist
public void prePersist() {
createdAt = new Date();
}
// -- Getters & Setters -- //
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public List<PetitionEntity> getListPetitionEntity() {
return listPetitionEntity;
}
public void setListPetitionEntity(List<PetitionEntity> listPetitionEntity) {
this.listPetitionEntity = listPetitionEntity;
}
}
PetitionEntity
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
#Entity
#Table(name = "petition")
public class PetitionEntity implements Serializable {
private static final long serialVersionUID = 1L;
// -- Attributes -- //
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "device_id")
private DeviceEntity device;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserEntity user;
#Column(name = "switch_on")
private Boolean switchOn;
#Column(name = "temp_ref")
private Float tempRef;
#Column(name = "mode")
private Integer mode;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd/MM/yyyy hh:mm:ss")
#Column(name = "time_to_off")
private Date timeToOff;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd/MM/yyyy hh:mm:ss")
#Column(name = "created_at")
private Date createdAt;
// -- Methods -- //
#PrePersist
public void prePersist() {
createdAt = new Date();
}
// -- Getters & Setters -- //
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public DeviceEntity getDevice() {
return device;
}
public void setDevice(DeviceEntity device) {
this.device = device;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public Boolean getSwitchOn() {
return switchOn;
}
public void setSwitchOn(Boolean switchOn) {
this.switchOn = switchOn;
}
public Float getTempRef() {
return tempRef;
}
public void setTempRef(Float tempRef) {
this.tempRef = tempRef;
}
public Integer getMode() {
return mode;
}
public void setMode(Integer mode) {
this.mode = mode;
}
public Date getTimeToOff() {
return timeToOff;
}
public void setTimeToOff(Date timeToOff) {
this.timeToOff = timeToOff;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
}
I have this tables created in MySQL workbench. Here is the code:
Device table
CREATE TABLE `device` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(80) DEFAULT NULL,
`type` varchar(80) DEFAULT NULL,
`model` varchar(80) DEFAULT NULL,
`enabled` tinyint DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
User table
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(80) DEFAULT NULL,
`password` varchar(80) DEFAULT NULL,
`name` varchar(80) DEFAULT NULL,
`surname` varchar(80) DEFAULT NULL,
`enabled` tinyint DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`uername` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Petition table
CREATE TABLE `petition` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int DEFAULT NULL,
`device_id` int DEFAULT NULL,
`switch_on` tinyint DEFAULT NULL,
`temp_ref` float DEFAULT NULL,
`mode` int DEFAULT NULL,
`time_to_off` datetime DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_user_table_id_idx` (`user_id`),
KEY `fk_device_table_id_idx` (`device_id`),
CONSTRAINT `fk_device_table_id` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`),
CONSTRAINT `fk_user_table_id` FOREIGN KEY (`user_id`) REFERENCES `db_domotic_house`.`user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
This is my application.properties:
spring.datasource.url=jdbc:mysql://localhost/domotic_house?serverTimezone=Europe/Madrid
spring.datasource.username=root
spring.datasource.password=sasa
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=none
logging.level.org.hibernate.SQL=debug
When I run the application in IntelliJ I can see in MySQL workbench that hibernate has created some new tables that I don't want.
This are the code of that tables:
device_list_petition_entity
CREATE TABLE `device_list_petition_entity` (
`device_entity_id` int NOT NULL,
`list_petition_entity_id` int NOT NULL,
UNIQUE KEY `UK_j196d5ebc0t1v3ak5xik9cfoc` (`list_petition_entity_id`),
KEY `FKl9kjtuj8w6t07u9et7u8573hg` (`device_entity_id`),
CONSTRAINT `FK5lupuetde9paakuy8b5g86vmb` FOREIGN KEY (`list_petition_entity_id`) REFERENCES `petition` (`id`),
CONSTRAINT `FKl9kjtuj8w6t07u9et7u8573hg` FOREIGN KEY (`device_entity_id`) REFERENCES `device` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
user_list_petition_entity
CREATE TABLE `user_list_petition_entity` (
`user_entity_id` int NOT NULL,
`list_petition_entity_id` int NOT NULL,
UNIQUE KEY `UK_9ce6ulb7rn1mjpqesb0set963` (`list_petition_entity_id`),
KEY `FKfk2tckk9hrc0krq0yka2bspnf` (`user_entity_id`),
CONSTRAINT `FK5sturgl5us0uw35douhvpkug9` FOREIGN KEY (`list_petition_entity_id`) REFERENCES `petition` (`id`),
CONSTRAINT `FKfk2tckk9hrc0krq0yka2bspnf` FOREIGN KEY (`user_entity_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
I don't know what I'm doing wrong. Can someone help? Thanks!

spring jpa #ManyToOne not generating foreign keys

When I generate the tables it generates it ok, but JPA is not generating any FK.
When I tell mysql to show me what it did to create the table it shows the lack of the foreign key constraint. It only generates KEY and it is not adding the foreign key.
mysql> show create table view_display;
| view_display | CREATE TABLE view_display (
dtype varchar(31) NOT NULL,
id bigint(20) NOT NULL,
col int(11) NOT NULL,
row int(11) NOT NULL,
chart_id bigint(20) DEFAULT NULL,
view_id bigint(20) NOT NULL,
data_source_id bigint(20) DEFAULT NULL,
PRIMARY KEY (id),
KEY FKqllm025dtc51xf38qdr5je52q (chart_id),
KEY FKb1gu01sld2cm281oa88pjq9ia (view_id),
KEY FK2hljr3ohtf3vql7hhvyqbm2mc (data_source_id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
View.java
#Entity
#Table(name="view")
public class View {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "view_seq")
#SequenceGenerator(name = "view_seq", sequenceName = "view_seq", allocationSize = 1)
private Long id;
private String name;
#Column(name ="is_default",nullable= false,columnDefinition="tinyint(1) default 0")
private boolean isDefault;
#ManyToOne
#JoinColumn(name="userId",insertable=true, updatable= false,nullable=true)
private User user;
#OneToOne
#JoinColumn(name="cvId",insertable=true, updatable= false,nullable=true,unique=true)
private CV cv;
#OneToMany(mappedBy="view")
private List<ViewDisplay> viewDisplay;
// getters and setters....
}
ViewDisplay.java
#Entity
#Table(name = "view_display")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class ViewDisplay {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "view_display_seq")
#SequenceGenerator(name = "view_display_seq", sequenceName = "view_display_seq", allocationSize = 1)
private Long id;
#ManyToOne
#JoinColumn(name="chartId",insertable=true, updatable= true, nullable = true)
private Chart chart;
#ManyToOne
#JoinColumn(name = "viewId", insertable = true, updatable = true, nullable=false)
private View view;
private int col;
private int row;
public ViewDisplay() {}
public ViewDisplay(Long id, Chart chart, View view, int col, int row) {
super();
this.id = id;
this.chart = chart;
this.view = view;
this.col = col;
this.row = row;
}
// getters and setters...
}

JPA one_to_one relationship not retrieve the auto increment

I have 2 Mysql tables users and empires,
users
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(45) CHARACTER SET utf8 NOT NULL,
`password` varchar(12) CHARACTER SET utf8 NOT NULL,
`country` varchar(25) CHARACTER SET utf8 NOT NULL,
`activated` tinyint(3) unsigned NOT NULL DEFAULT '0',
`activationcode` varchar(45) CHARACTER SET utf8 NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `email_UNIQUE` (`email`),
KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
and empires
CREATE TABLE `empires` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pid` int(10) unsigned NOT NULL,
`name` varchar(45) CHARACTER SET utf8 NOT NULL,
`notes` varchar(90) CHARACTER SET utf8 NOT NULL,
`world` tinyint(3) unsigned NOT NULL,
`island` smallint(5) DEFAULT NULL,
`population` int(10) unsigned DEFAULT '20',
`gold` decimal(20,0) DEFAULT '500',
`percent` decimal(9,5) DEFAULT '50.00000',
`logo` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`,`pid`),
KEY `name` (`name`),
KEY `world` (`world`),
KEY `FK_pid` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
and i have these entities :
package boddooo.entity;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private int activated=1;
private String activationcode="";
private String country;
private String email;
private String password;
public User(){}
public User(int id,String email,String password,String country) {
this.id=id;
this.email=email;
this.password=password;
this.country=country;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public int getActivated() {
return this.activated;
}
public void setActivated(int activated) {
this.activated = activated;
}
public String getActivationcode() {
return this.activationcode;
}
public void setActivationcode(String activationcode) {
this.activationcode = activationcode;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}
and
package boddooo.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
#Entity
#Table(name="empires")
#NamedQuery(name="Empire.findAll", query="SELECT e FROM Empire e")
public class Empire implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private int pid;
private BigDecimal gold=BigDecimal.valueOf(500);
private String logo="";
private String name;
private String notes;
private BigDecimal percent=BigDecimal.valueOf(50.0000);
private int population=10;
private int world;
private int island;
#OneToOne
#PrimaryKeyJoinColumn(name="pid")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Empire(){}
public Empire(int id,String name,String logo,String notes,int world) {
this.id=id;
this.name=name;
this.logo=logo;
this.notes=notes;
this.world=world;
}
public int getPid() {
return pid;
}
public void setPid(int pid){
this.pid=pid;
}
public int getWorld() {
return world;
}
public void setWorld(int world) {
this.world = world;
}
public int getIsland() {
return island;
}
public void setIsland(int island) {
this.island = island;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public BigDecimal getGold() {
return this.gold;
}
public void setGold(BigDecimal gold) {
this.gold = gold;
}
public String getLogo() {
return this.logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getNotes() {
return this.notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public BigDecimal getPercent() {
return this.percent;
}
public void setPercent(BigDecimal percent) {
this.percent = percent;
}
public int getPopulation() {
return this.population;
}
public void setPopulation(int population) {
this.population = population;
}
}
and this function to insert the new objets to the database
public void createUser() throws NamingException, NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException{
Context icontext=new InitialContext();
ut=(UserTransaction)icontext.lookup("java:comp/UserTransaction");
ut.begin();
User user=new User();
user.setEmail(email);
user.setPassword(password);
user.setCountry(country);
em.persist(user);
Empire emp=new Empire();
emp.setName(empirename);
emp.setNotes(empirenotes);
emp.setLogo(empirelogo);
emp.setWorld(worldid);
emp.setUser(user);
em.persist(emp);
ut.commit();
}
this is one to one relationship which
empires.pid=users.id
but when i call this method it insert users and empires but the pid field in empires has 0 value instead of the auto increment value.
am i miss something? please help
#PrimaryKeyJoinColumn indicates that the field used is this entities primary key, and as such is effectively read-only. This is mostly used when you have an entity that spans multiple tables.
#JoinColumn is what you should be using as it indicates the specified column is a traditional foreign key and that you want the target value to be used to set this field.
#OneToOne
#JoinColumn(name="pid")
private User user;
You should use #JoinColumn(name="fk_id") along with #OneToOne. More details at JSR 317: JavaTM Persistence API, Version 2.0

org.hibernate.MappingException: Unable to find column with logical name OnetoOne Mapping

I'm newb to JPA. I'm having trouble with defining OneToOne bidirectional flow on my classes.
UserInfo.java:
#Entity
#Table(name="UserInfo")
public class UserInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer idUserInfo;
private String firstName;
private String lastName;
#OneToOne(mappedBy="UserInfo")
private LoginInfo loginInfo;
LoginInfo.java:
#Entity
#Table(name="LoginInfo")
public class LoginInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer idLoginInfo;
#Column(name="emailId")
private String emailId;
//bidirectional one to one association to UserInfo
#OneToOne
#JoinColumn(name="emailId", referencedColumnName="loginInfo")
private UserInfo userInfo;
private String sessionId;
private String password;
Here's sql to create those tables:
CREATE TABLE `LoginInfo` (
`emailId` varchar(45) NOT NULL,
`idLoginInfo` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`idLoginInfo`),
UNIQUE KEY `emailId_UNIQUE` (`emailId`),
UNIQUE KEY `id_UNIQUE` (`idLoginInfo`)
);
DROP TABLE IF EXISTS `UserInfo`;
CREATE TABLE `UserInfo` (
`idUserInfo` int(11) NOT NULL AUTO_INCREMENT,
`firstName` varchar(45) NOT NULL,
`lastName` varchar(45) NOT NULL,
`loginInfo` varchar(45) NOT NULL,
PRIMARY KEY (`idUserInfo`),
UNIQUE KEY `idUserInfo_UNIQUE` (`idUserInfo`),
UNIQUE KEY `loginInfo_UNIQUE` (`loginInfo`),
CONSTRAINT `loginInfo` FOREIGN KEY (`loginInfo`) REFERENCES `LoginInfo` (`emailId`) ON DELETE CASCADE ON UPDATE CASCADE
);
When I start the Tomcat server, I'm getting the follow exception on ContextInitialization.
Caused by: org.hibernate.MappingException: Unable to find column with logical name: loginInfo in org.hibernate.mapping.Table(UserInfo) and its related supertables and secondary tables
But the column do exist on the UserInfo table. Can somebody please help me if the mapping is right?
Thanks
Invalid association : #JoinColumn(name="emailId", referencedColumnName="loginInfo")
#Entity
#Table(name="UserInfo")
public class UserInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer idUserInfo;
private String firstName;
private String lastName;
#OneToOne(mappedBy = "userInfo", cascade = CascadeType.ALL)
private LoginInfo loginInfo;
#Entity
#Table(name="LoginInfo")
public class LoginInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer idLoginInfo;
#Column(name="emailId")
private String emailId;
//bidirectional one to one association to UserInfo
#OneToOne
#PrimaryKeyJoinColumn
private UserInfo userInfo;
private String sessionId;
private String password;
After reading about OneToOne mapping, annotations and some trial & error, I was able to use the LoginInfo and UserInfo tables successfully. In my question above, it has some invalid mappings. The requirement was that UserInfo be the owner entity and LoginInfo as the child entity. So as suggested by ashokhein, I used PrimaryKeyJoinColumn annotation. This is how my tables look like now.
CREATE TABLE `login_info` (
`user_info_id` bigint(100) NOT NULL,
`email_id` varchar(45) NOT NULL,
PRIMARY KEY (`user_info_id`),
UNIQUE KEY `email_id_UNIQUE` (`email_id`),
UNIQUE KEY `user_info_id_UNIQUE` (`user_info_id`),
CONSTRAINT `FK_login_info_user_info` FOREIGN KEY (`user_info_id`) REFERENCES `user_info` (`user_info_id`) ON DELETE CASCADE ON UPDATE CASCADE);
CREATE TABLE `user_info` (
`user_info_id` bigint(100) NOT NULL AUTO_INCREMENT,
`first_name` varchar(50) DEFAULT NULL,
`last_name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`user_info_id`),
UNIQUE KEY `user_info_id_UNIQUE` (`user_info_id`));
This is how my classes look like:
UserInfo:
#Entity
#Table(name = "user_info")
public class UserInfo {
#Id
#Column(name = "user_info_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer userId;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private LoginInfo loginInfo;
//Getters and setters
LoginInfo:
#Entity
#Table(name = "login_info")
public class LoginInfo {
#Id
#Column(name = "user_info_id")
#GeneratedValue(generator = "generator")
#GenericGenerator(name = "generator", strategy = "foreign", parameters = #Parameter(name = "property", value = "userInfo"))
private Integer id;
#OneToOne
#PrimaryKeyJoinColumn
private UserInfo userInfo;
#Column(name = "email_id")
private String emailId;
//Getters and setters
And this is how I create and save the entities to the table:
UserInfo userInfo = new UserInfo();
userInfo.setFirstName(registerUserRequest.getFirstName());
userInfo.setLastName(registerUserRequest.getLastName());
LoginInfo loginInfo = userInfo.getLoginInfo();
if(loginInfo == null) {
loginInfo = new LoginInfo();
}
loginInfo.setEmailId(registerUserRequest.getEmailId());
loginInfo.setUserInfo(userInfo);
userInfo.setLoginInfo(loginInfo);
if(userService.create(userInfo)) {
logger.debug("User created successfully");
} else {
throw new UserAlreadyExistException();
}
During the course of getting to this solution, I encountered bunch of hibernate exceptions and issues. Here's some(if it helps someone)
Error: identifier of an instance of was altered from 14 to 14
Solution: The primary key on the Entity classes where different types initially. The column user_info_id was declared as Integer in UserInfo and long in LoginInfo.
Error: attempted to assign id from null one-to-one property
Solution: While creating the UserInfo object, I did "userInfo.setLoginInfo(loginInfo)" but did not set "loginInfo.setUserInfo(userInfo)". After fixing that, it was fine.
Note: If you see a better way to do the same, please do comment here and let me know. Thanks in advance.

Hibernate error: Could not determine type for: com.mysql.jdbc.Blob

I'm working on a project with Hibernate and MySQL. In one of my model objects, I declared a property "image" whose type is Blob, and I used com.mysql.jdbc.Blob. But when I ran that program, an error occurred: org.hibernate.MappingException: Could not determine type for: com.mysql.jdbc.Blob, at table: SPOT, for columns: [org.hibernate.mapping.Column(image)].
Here is source code of data model:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "SPOT", catalog = "ar", uniqueConstraints = #UniqueConstraint(columnNames = "name"))
#XmlRootElement(name = "spot")
public class Spot extends BaseIdObject {
private Double axisX;
private Double axisY;
private String address;
private String spotType;
private String description;
private String phoneNumber;
private String website;
private Blob image;
#Column(name = "axis_x", precision = 22, scale = 0)
#NotNull
public Double getAxisX() {
return this.axisX;
}
public void setAxisX(Double axisX) {
this.axisX = axisX;
}
#Column(name = "axis_y", precision = 22, scale = 0)
#NotNull
public Double getAxisY() {
return this.axisY;
}
public void setAxisY(Double axisY) {
this.axisY = axisY;
}
#Column(name = "address", length = 200)
#NotNull
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
#Column(name = "spot_type", length = 50)
#NotNull
public String getSpotType() {
return this.spotType;
}
public void setSpotType(String spotType) {
this.spotType = spotType;
}
#Column(name = "description", length = 2000)
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
#Column(name = "phone_number", length = 30)
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
And here is the corresponding DDL of table SPOT:
DROP TABLE IF EXISTS `spot`;
/*!40101 SET #saved_cs_client = ##character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `spot` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(200) DEFAULT NULL,
`AXIS_X` double NOT NULL,
`AXIS_Y` double NOT NULL,
`ADDRESS` varchar(200) DEFAULT NULL,
`SPOT_TYPE` varchar(50) NOT NULL,
`DESCRIPTION` varchar(2000) DEFAULT NULL,
`PHONE_NUMBER` varchar(30) DEFAULT NULL,
`WEBSITE` varchar(200) DEFAULT NULL,
`IMAGE` blob,
PRIMARY KEY (`ID`),
UNIQUE KEY `SPOT_ID_UNIQUE` (`ID`),
UNIQUE KEY `SPOT_NAME_UNIQUE` (`NAME`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = #saved_cs_client */;
I searched on Internet and found a suggestion of using java.sql.Blob. But when I changed to that type, another error occurred, because in my program, I did some processes with XML on that model object, so it cannot handle the interface java.sql.Blob. So what I have to do to keep the data type com.mysql.jdbc.Blob and the program still run normally with Hibernate? Thank you so much.
I'd say that it's not right to depend on the implementation details for the JDBC driver. I would review your dependency, and try to make it a soft dependency. If you really need to keep this hard dependency, you'll need to implement an UserType capable of handling com.mysql.jdbc.Blob. I don't know the details about this implementation, but you can extend Hibernate's BlobType as MySQLBlobType, and annotate your model property with #Type annotation, specifying this MySQLBlobType:
https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/java/org/hibernate/type/BlobType.java
https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/test/java/org/hibernate/test/annotations/type/Dvd.java