spring jpa #ManyToOne not generating foreign keys - mysql

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...
}

Related

Change foreign key constraint to unique key on bridge table many to many

I am tasked to change the foreign key constraint on a bridge table to a unique key constraint via mysql script. I am on a spring boot project that uses flyway for database migrations.
This is the model class for the first table
#Data
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "payment_transaction_status_update")
public class PaymentTransactionStatusUpdate {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#Column(name = "file_tag")
private String fileTag;
#Column(name = "location")
private String location;
#Column(name = "file_key")
private String fileKey;
#Column(name = "file_name")
private String fileName;
#Column(name = "bucket")
private String bucket;
#Column(name = "server_side_encryption")
private String serverSideEncryption;
#Column(name = "batch_transaction_update_status")
#Enumerated(EnumType.STRING)
private BatchTransactionUpdateStatus batchTransactionUpdateStatus;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at", length = 19)
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_at", length = 19)
private Date updatedAt;
#Column(name = "initiator_email")
private String initiatorEmail;
#Column(name = "approver_email")
private String approverEmail;
}
This is the model class for the second table
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Data
#Entity
#Table(name = "payment_transaction")
public class AllPaymentTransaction implements Serializable, IPaymentTransaction {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "payable_type")
private String payableType;
#Column(name = "client_id")
private String clientId;
#Column(name = "payable_model_id")
private Long payableModelId;
#Column(name = "internal_reference", unique = true, nullable = false)
private String reference;
#Column(name = "provider_reference", length = 64)
private String providerReference;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at")
private Date createdAt;
}
So currently the following is the sql script for the bridge table
CREATE TABLE `payment_transaction_status_update_record_status` (
`id` int NOT NULL AUTO_INCREMENT,
`payment_transaction_status_update_id` int NOT NULL,
`payment_transaction_id` bigint NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE_01` (`id`),
KEY `Foreign_IDs_IDX_01`
(`payment_transaction_status_update_id`,`payment_transaction_id`),
KEY `FK_payment_transaction_id_idx_01` (`payment_transaction_id`),
CONSTRAINT `FK_payment_transaction_id_01` FOREIGN KEY (`payment_transaction_id`)
REFERENCES `payment_transaction` (`id`),
CONSTRAINT `FK_payment_transaction_status_update_id_01` FOREIGN KEY
(`payment_transaction_status_update_id`) REFERENCES
`payment_transaction_status_update` (`id`)
) ENGINE=InnoDB;
Now I want to use the 'reference' column with the 'unique' index as the foreign key on this bridge table.
I have done the follwing
ALTER TABLE `payment_transaction_status_update_record_status`
DROP COLUMN `payment_transaction_id`,
DROP CONSTRAINT `FK_payment_transaction_id_01`,
DROP CONSTRAINT `FK_payment_transaction_status_update_id_01`,
DROP KEY `FK_payment_transaction_id_idx_01`,
DROP KEY `Foreign_IDs_IDX_01`;
ALTER TABLE `payment_transaction_status_update_record_status`
ADD COLUMN `payment_transaction_reference` VARCHAR(255) NOT NULL,
ADD KEY `Foreign_IDs_IDX_02`
(`payment_transaction_status_update_id`,`payment_transaction_reference`),
ADD KEY `FK_payment_transaction_reference_referencex_01`
(`payment_transaction_reference`),
ADD CONSTRAINT `FK_payment_transaction_reference_01` FOREIGN KEY
(`payment_transaction_reference`) REFERENCES `payment_transaction`
(`internal_reference`);
The bridge class is as follows
#Data
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "payment_transaction_status_update_record_status")
public class PaymentTransactionStatusUpdateRecordStatus {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#ManyToOne
#JoinColumn(name = "payment_transaction_status_update_id", referencedColumnName = "id", nullable = false)
private PaymentTransactionStatusUpdate paymentTransactionStatusUpdate;
#ManyToOne
#JoinColumn(name = "payment_transaction_id", referencedColumnName = "id", nullable = false)
private AllPaymentTransaction paymentTransaction;
}
Now when trying to populate the bridge table I am setting only the reference column on the AllPaymentTransaction class as well as setting setting the PaymentTransactionStatusUpdate via the id. I have also changed it to
#ManyToOne
#JoinColumn(name = "payment_transaction_reference", referencedColumnName = "reference", nullable = false)
private AllPaymentTransaction paymentTransaction;
While trying to populate the bridge table I get this error.
org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : co.onefi.services.xps.models.PaymentTransactionStatusUpdateRecordStatus.paymentTransaction -> co.onefi.services.xps.models.AllPaymentTransaction"
For more info: I am setting only the reference on the AllTransactionPayment object of the
bridge table.

With jpa, many side of a one-to-many relationship is not getting persisted

I am having two entities having one-to-many & many-to-one relationship.
One side:
#Entity
#Table(name = "GAME_BLIND_STRUCTURE")
#Builder
#Getter
#Setter
public class GameBlindStructureEntity implements Serializable {
private static final long serialVersionUID = -7800120016594245121L;
#Id
#Column(name = "BLIND_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long blindId;
#Column(name = "BLIND_STRUCTURE_NAME", unique = true)
private String blindStructureName;
#OneToMany(mappedBy = "gameBlindStructure")
private List<GameBlindStructureDetailsEntity> gameBlindStructureDetailsEntities;
}
Many-sided entity:
#Entity
#Table(name = "GAME_BLIND_STRUCTURE_DETAILS")
#Builder
#Getter
#Setter
public class GameBlindStructureDetailsEntity implements Serializable {
private static final long serialVersionUID = -7800120016594245121L;
#Id
#Column(name = "BLIND_DETAILS_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long blindDetailsId;
#ManyToOne
#JoinColumn(name = "BLIND_ID")
private GameBlindStructureEntity gameBlindStructure;
#Column(name = "LEVEL")
private String level;
#Column(name = "SMALL_BLIND")
private Integer smallBlind;
#Column(name = "BIG_BLIND")
private Integer bigBlind;
#Column(name = "ANTE")
private Integer ante;
#Column(name = "TIME_BANK")
private String timeBank;
#Column(name = "MINUTES")
private Integer minutes;
}
In the service method, I am trying to persist these entities to database.
public BlindStructureResponseDto createBlindStructure(BlindStructureDto blindStructureDto) {
GameBlindStructureEntity gameBlindStructureEntity = GameBlindStructureEntity.builder()
.blindStructureName(blindStructureDto.getName())
.build();
List<BlindStructureDetailsDto> blindStructureDetailsDtos = blindStructureDto.getBlindStructureDetailsDtos();
List<GameBlindStructureDetailsEntity> gameBlindStructureDetailsEntities = new ArrayList<>();
for(BlindStructureDetailsDto blindStructureDetailsDto : blindStructureDetailsDtos) {
GameBlindStructureDetailsEntity gameBlindStructureDetailsEntity = mapper.convertToGameStructureDetailsEntity(blindStructureDetailsDto);
gameBlindStructureDetailsEntity.setGameBlindStructure(gameBlindStructureEntity);
gameBlindStructureDetailsEntities.add(gameBlindStructureDetailsEntity);
}
gameBlindStructureEntity.setGameBlindStructureDetailsEntities(gameBlindStructureDetailsEntities);
GameBlindStructureEntity savedEntity = blindStructureRepository.save(gameBlindStructureEntity);
BlindStructureResponseDto blindStructureResponseDto = BlindStructureResponseDto.builder()
.name(savedEntity.getBlindStructureName())
.blindId(savedEntity.getBlindId())
.build();
return blindStructureResponseDto;
}
Though the entity on one-side is getting persisted to the database, the many sided entity is not getting saved.
Here is the ddl script:
DROP TABLE IF EXISTS `GAME_BLIND_STRUCTURE`;
CREATE TABLE `GAME_BLIND_STRUCTURE`
( `BLIND_ID` INT AUTO_INCREMENT,
`BLIND_STRUCTURE_NAME` VARCHAR(255) NOT NULL,
PRIMARY KEY (`BLIND_ID`),
UNIQUE KEY `UNIQUE_BLIND_STRUCTURE_NAME` (`BLIND_STRUCTURE_NAME`)
) ENGINE=INNODB DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `GAME_BLIND_STRUCTURE_DETAILS`;
CREATE TABLE `GAME_BLIND_STRUCTURE_DETAILS`
(`BLIND_DETAILS_ID` INT AUTO_INCREMENT,
`BLIND_ID` INT NOT NULL,
`LEVEL` VARCHAR(255) NOT NULL,
`SMALL_BLIND` INT NOT NULL,
`BIG_BLIND` INT NOT NULL,
`ANTE` INT NOT NULL,
`TIME_BANK`VARCHAR(255) NOT NULL,
`MINUTES` INT NOT NULL,
PRIMARY KEY(`BLIND_DETAILS_ID`),
CONSTRAINT `FK_BLIND_ID` FOREIGN KEY (`BLIND_ID`) REFERENCES `GAME_BLIND_STRUCTURE` (`BLIND_ID`)
)ENGINE=INNODB DEFAULT CHARSET=latin1;
You're missing CascadeType.ALL on your #OneToMany annotation, code should be as follows:
#OneToMany(mappedBy = "gameBlindStructure", cascade = CascadeType.ALL)
private List<GameBlindStructureDetailsEntity> gameBlindStructureDetailsEntities;

Spring JPA | Search in Many to Many Relationship

I have 2 tables Book and Author in a Many to Many Relationship using a candidate key table author_book which has primary keys of both author and Book.
I'm trying to get all books from a given author by AUTHOR_ID, maybe after if it works I'll try to do search by name
create table author_book(
`AUTHOR_ID` INT,
`BOOK_ID` INT
);
`
create table author(
`AUTHOR_ID` int auto_increment,
`FIRST_NAME` varchar(255),
`LAST_NAME` varchar(255),
`EMAIL` varchar(30),
`CONTACT_NO` VARCHAR(10),
primary key(AUTHOR_ID)
);
create table book(
`BOOK_ID` int auto_increment,
`TITLE` varchar(255),
`SUBJECT` varchar(255),
`PUBLISHED_YEAR` int,
`ISBN` varchar(30),
`QUANTITY` int,
`SHELF_DETAILS` varchar(255),
`PUBLISHER_ID` int,
`BOOK_COST` INT,
primary key(BOOK_ID)
);
I decided I'll create AUTHOR_NAME using CONCAT
I tried this query for search by author_id
#Query("select b from Books b where b.bookId in (select a.bookId from author_book a where a.author_id = :Id)")
but I'm getting error that author_book is not mapped so do I need to create another entity for this class to perform any operations b/w these 2 class? I'm also not sure if nested queries work in JPQL, this was basically a hunch.
My Books Entity
#Entity
#Table(name = "book")
public class Books implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="BOOK_ID")
private int bookId;
#Column(name="TITLE")
private String title;
#Column(name="SUBJECT")
private String subject;
#Column(name="PUBLISHED_YEAR")
private int publishedYear;
#Column(name="ISBN")
private String isbn;
#Column(name="QUANTITY")
private int quantity;
#Column(name="SHELF_DETAILS")
private String shelfDetails;
#Column(name="BOOK_COST")
private int bookCost;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "author_book",
joinColumns = { #JoinColumn(name = "BOOK_ID") },
inverseJoinColumns = { #JoinColumn(name = "AUTHOR_ID") })
private Set<Authors> authors = new HashSet<Authors>();
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="PUBLISHER_ID")
private Publishers publisher;
// getters and setters
}
My Authors Entity
#Entity
#Table(name="author")
public class Authors {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="AUTHOR_ID")
private int authorId;
#Column(name="FIRST_NAME")
private String firstName;
#Column(name="LAST_NAME")
private String lastName;
#Column(name="EMAIL")
private String email;
#Column(name="CONTACT_NO")
private String contactNo;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "authors")
private Set<Books> books = new HashSet<Books>();
// Getters and setters
}
You should add mappedBy things in Authors Entity.
#ManyToMany(mappedBy="authors", fetch=FetchType.LAZY)
private Set<Books> books = new HashSet<Books>();

I can not generate auto-incremented Id and hibernate always generate 1 as Id

I am a bit disconcerted with this and I am asking for help just in order to understand what is happening.
So, I have this table (DDL):
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(45) NOT NULL,
`lastname` varchar(45) NOT NULL,
`email` varchar(60) NOT NULL,
`password` varchar(100) NOT NULL,
`enabled` tinyint(1) NOT NULL,
`created_at` datetime DEFAULT NULL,
`image_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email_UNIQUE` (`email`),
KEY `FK17herqt2to4hyl5q5r5ogbxk9` (`image_id`),
CONSTRAINT `FK17herqt2to4hyl5q5r5ogbxk9` FOREIGN KEY (`image_id`) REFERENCES `images` (`id`),
CONSTRAINT `fk_users_images1` FOREIGN KEY (`image_id`) REFERENCES `images` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
And my entity:
#Entity
#Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 6304869652591140818L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#Column(name = "firstname")
private String firstname;
#Column(name = "lastname")
private String lastname;
#Column(name = "email")
private String email;
#Column(name = "password")
#Transient
private String password;
#Column(name = "enabled")
private int enabled;
#Column(name = "created_at")
private LocalDateTime createdAt;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "users_has_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
#MapsId
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Image image;
// Setters and Getters
}
I am trying to persist a new User with this code:
#PersistenceContext
private EntityManager em;
#Transactional
public void createUser(NewUserDto newUser) {
User user = new User();
user.setFirstname(newUser.getFirstname());
user.setLastname(newUser.getLastname());
user.setEmail(newUser.getEmail());
user.setEnabled(ENABLED);
user.setPassword(bCryptPasswordEncoder.encode(newUser.getPassword()));
Image userImage = imageService.getImageById(1L);
user.setProfileImage(userImage);
Set<Role> roles = new HashSet<Role>();
Role role = roleRepository.findByName(newUser.getRole());
roles.add(role);
user.setRoles(roles);
if (user.getId() == null) {
em.persist(user);
em.flush();
} else {
em.merge(user);
}
}
The thing is that when I debug I see that always generates id=1 for the new user.
But in the database, I see all correct.
And when i search for all users i get the following:
public List<User> getAll() {
return userRepository.findAll();
}
The same JPDA ObjectReference.
Any help will be welcomed.
Thanks.
(Apologies for not having enough reputation to leave a comment)
I do not understand your question clearly. Anyway i will try to explain based on what I think is your problem.
By default, the starting value for AUTO_INCREMENT is 1, and it will
increment by 1 for each new record. So that behavior is expected.
If you want it to start with a value that is not 1, then you must use
a GenerationType.SEQUENCE with appropriate changes.
Image1: You have mentioned that the values are getting entered into
the database correctly and this shows that the Id values are being
generated correctly
Image2: users is a Javascript array. Index values of javascript
arrays always start from zero. That is just the index value and NOT
the id value. Similarly, the id mentioned on the right is the
javascript's internal object id and not the actual Id of your user.
To see the real id of the user, expand the user at position 0.
If this does not answer your questions, kindly elaborate your question and what exactly is the error or issue.
The problem stems from a misunderstanding where Hibernate's fallback for GenerationType.AUTO is GenerationType.SEQUENCE, while what most people want is GenerationType.IDENTITY, so you can use the id the database assigns you. simply change the strategy to IDENTITY and your problem is solved.

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.