Spring REST API - User + his profile persist - java

I made an POST mapping myapp.com/users in my Spring App. When I send data to this mapping, I need create User and his Profile. Relation between them is OneToOne. Example:
AbstractEntity:
#MappedSuperclass
public abstract class AbstractEntity implements Serializable {
#Id
#GeneratedValue
private Integer id;
}
User: (Only important stuff)
#Entity
#Table(name = "Users")
public class User extends AbstractEntity {
#Basic(optional = false)
#Column(nullable = false, unique = true)
private String username;
#Basic(optional = false)
#Column(nullable = false)
private String password;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Profile profile;
public Profile getProfile() {
return profile;
}
public void setProfile(Profile profile) {
this.profile = profile;
}
}
Profile: (Only important stuff)
#Entity
#Table(name = "Profiles")
public class Profile extends AbstractEntity {
#Basic(optional = false)
#Column(nullable = false)
private String name;
#Basic(optional = false)
#Column(nullable = false)
private String surname;
#OneToOne
#JoinColumn(name = "USER_ID")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
And my RestController:
#RestController
#RequestMapping("/users")
public class UserController {
private static final Logger LOG = LoggerFactory.getLogger(UserController.class);
private final UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
/**
* Registers a new user.
*
* #param user User data
*/
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> register(#RequestBody User user) {
try {
userService.persist(user);
LOG.debug("User {} successfully registered.", user);
final HttpHeaders headers = RestUtils.createLocationHeaderFromCurrentUri("/current");
return new ResponseEntity<>(headers, HttpStatus.CREATED);
}
catch (TransactionSystemException e) {
throw new PersistenceException(e.getOriginalException());
}
}
}
How can I send both User and Profile? #RequestBody can receive only one Entity what I know. I tried this JSON data:
{
"username": "admin",
"password": "1234",
"profile":{
"name": "User",
"surname": "Test"
}
}
But even User and Profile are created, there is no relation between them (USER_ID not set).
Here are the table definitions:
CREATE TABLE `profiles` (
`ID` int(11) NOT NULL,
`BIRTHDATE` date DEFAULT NULL,
`DESCRIPTION` varchar(255) DEFAULT NULL,
`GENDER` varchar(255) DEFAULT NULL,
`IMAGE` varchar(255) DEFAULT NULL,
`NAME` varchar(255) NOT NULL,
`SURNAME` varchar(255) NOT NULL,
`USER_ID` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `sequence` (
`SEQ_NAME` varchar(50) NOT NULL,
`SEQ_COUNT` decimal(38,0) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `sequence` (`SEQ_NAME`, `SEQ_COUNT`) VALUES
('SEQ_GEN', '50');
CREATE TABLE `users` (
`ID` int(11) NOT NULL,
`BLOCKED` tinyint(1) NOT NULL DEFAULT 0,
`EMAIL` varchar(255) NOT NULL,
`PASSWORD` varchar(255) NOT NULL,
`ROLE` varchar(255) DEFAULT NULL,
`USERNAME` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `profiles`
ADD PRIMARY KEY (`ID`),
ADD KEY `FK_profiles_USER_ID` (`USER_ID`);
ALTER TABLE `sequence`
ADD PRIMARY KEY (`SEQ_NAME`);
ALTER TABLE `users`
ADD PRIMARY KEY (`ID`),
ADD UNIQUE KEY `EMAIL` (`EMAIL`),
ADD UNIQUE KEY `USERNAME` (`USERNAME`);
ALTER TABLE `profiles`
ADD CONSTRAINT `FK_profiles_USER_ID` FOREIGN KEY (`USER_ID`) REFERENCES `users` (`ID`);

I assume you have an attribute annotated with #Id.
You have to add the mappedBy to the owner of the relationship, in your case User. Try the following modifications
#Entity
#Table(name = "Users")
public class User extends AbstractEntity {
#Basic(optional = false)
#Column(nullable = false, unique = true)
private String username;
#Basic(optional = false)
#Column(nullable = false)
private String password;
//Edited here
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Profile profile;
public Profile getProfile() {
return profile;
}
public void setProfile(Profile profile) {
this.profile = profile;
}
}
And
#Entity
#Table(name = "Profiles")
public class Profile extends AbstractEntity {
#Basic(optional = false)
#Column(nullable = false)
private String name;
#Basic(optional = false)
#Column(nullable = false)
private String surname;
//Edited here
#OneToOne
#JoinColumn
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

Related

Hibernate ignores #AttributeOverrides annotation and creates columns in a wrong table

I have 2 SQL tables:
Users:
CREATE TABLE users
(
id BIGINT PRIMARY KEY DEFAULT nextval('global_seq'),
/* email, password, other fields */
);
Users_avatars:
CREATE TABLE users_avatars
(
user_id BIGINT NOT NULL,
file_name VARCHAR,
file_path VARCHAR,
FOREIGN KEY (user_id) REFERENCES users (id)
);
However, why I try to map it with Hibernate it creates file_name and file_path inside the users table.
My classes are the following:
#Entity
#Table(name = "users")
#SecondaryTable(name = "users_avatars",
pkJoinColumns = #PrimaryKeyJoinColumn(name = "user_id", referencedColumnName = "id"))
public class User extends EntityWithId
{
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "file_name", column = #Column(table = "users_avatars")),
#AttributeOverride(name = "file_path", column = #Column(table = "users_avatars"))
})
private FileInDb avatar;
public FileInDb getAvatar()
{
return avatar;
}
public void setAvatar(FileInDb avatar)
{
this.avatar = avatar;
}
}
And FileInDb class:
#Embeddable
#MappedSuperclass
public abstract class FileInDb
{
#Column(name = "file_name")
#NotNull
#NotBlank
private String fileName;
#Column(name = "file_path")
#NotNull
#NotBlank
private String filePath;
public String getFileName()
{
return fileName;
}
public void setFileName(String fileName)
{
this.fileName = fileName;
}
public String getFilePath()
{
return filePath;
}
public void setFilePath(String filePath)
{
this.filePath = filePath;
}
}
SQL script generated by Hibernate:
create table users (
id int8 not null,
file_name varchar(255),
file_path varchar(255),
/* Lots of other fields */
primary key (id)
)
create table users_avatars (
user_id int8 not null,
primary key (user_id)
)
Why is so? Please help. Thanks in advance.
You can use #OneToOne mapping with #MapsId to use the user_id as the id field for the user_avatars table

DuplicateMappingException on created_by field

I have 2 tables employee and employee_document. Here is the mysql query for two tables -
CREATE TABLE employee (
id int(11) unsigned NOT NULL,
name varchar(100) COLLATE utf8_unicode_ci NOT NULL,
email varchar(50) COLLATE utf8_unicode_ci NOT NULL,
password_hash varchar(100) COLLATE utf8_unicode_ci NOT NULL,
status int(11) NOT NULL,
creation_date bigint(20) NOT NULL,
created_by int(11) DEFAULT NULL,
update_date bigint(20) NOT NULL,
updated_by int(11) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE employee_document (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
employee_id int(11) unsigned NOT NULL,
file_id int(11) unsigned NOT NULL,
document_type varchar(50) COLLATE utf8_unicode_ci DEFAULT '',
status int(11) DEFAULT NULL,
creation_date bigint(20) DEFAULT NULL,
created_by int(11) unsigned NOT NULL,
update_date bigint(20) DEFAULT NULL,
updated_by int(11) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
In my spring boot project I used hibernate with JPA Data. Here are the java interpretation of these tables.
#MappedSuperclass
public abstract class AbstractTimestampEntity {
#Transient
Logger log = LoggerFactory.getLogger(AbstractTimestampEntity.class);
#Column(name = "creation_date", nullable = false, updatable=false)
private Long creationDate;
#Column(name = "update_date", nullable = false)
private Long updateDate;
#PrePersist
protected void onCreate() {
log.debug("onCreate");
updateDate = creationDate = System.currentTimeMillis();
}
#PreUpdate
protected void onUpdate() {
log.debug("onUpdate");
updateDate = System.currentTimeMillis();
}
}
#Entity
#Table(name = "employee")
public class Employee extends AbstractTimestampEntity implements Serializable {
private static final long serialVersionUID = 1L;
public static final Integer STATUS_INACTIVE = 0;
public static final Integer STATUS_ACTIVE = 1;
public static final Integer STATUS_ARCHIVED = -1;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Integer id;
#Column(name = "name", nullable = false)
public String name;
#Email
#Column(name = "email", nullable = false, unique = true)
public String email;
#JsonIgnore
#Column(name = "password_hash", nullable = false)
public String passwordHash;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "employee", fetch = FetchType.EAGER)
private Set<EmployeeDocument> documents;
#Max(1)
#Min(-1)
#Column(name = "status", nullable = false )
public Integer status;
#Column(name = "created_by", updatable = false)
public Integer createdById;
#Column(name = "updated_by")
public Integer updatedById;
}
#Entity
#Table(name = "employee_document")
public class EmployeeDocument extends AbstractTimestampEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Transient
public static final Integer STATUS_INACTIVE = 0;
#Transient
public static final Integer STATUS_ACTIVE = 1;
#Transient
public static final Integer STATUS_ARCHIVED = -1;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Integer id;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "employee_id", nullable = false)
public Employee employee;
#OneToOne
#JoinColumn(name = "file_id")
public EmployeeFile employeeFile;
#Max(1)
#Min(-1)
#Column(name = "status", nullable = false )
public Integer status;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "created_by", updatable = false)
#JsonBackReference
public Employee createdBy;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "updated_by")
#JsonBackReference
public Employee updatedBy;
}
This code does not execute, the app fails to start and throws DuplicateMappingException. Here's the full exception stack -
org.hibernate.DuplicateMappingException: Table [employee_document] contains physical column name [created_by] referred to by multiple physical column names: [createdBy], [created_by]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl$TableColumnNameBinding.bindPhysicalToLogical(InFlightMetadataCollectorImpl.java:922)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl$TableColumnNameBinding.addBinding(InFlightMetadataCollectorImpl.java:891)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.addColumnNameBinding(InFlightMetadataCollectorImpl.java:961)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.addColumnNameBinding(InFlightMetadataCollectorImpl.java:942)
at org.hibernate.cfg.Ejb3Column.addColumnBinding(Ejb3Column.java:407)
at org.hibernate.cfg.Ejb3Column.linkWithValue(Ejb3Column.java:369)
at org.hibernate.cfg.annotations.SimpleValueBinder.linkWithValue(SimpleValueBinder.java:431)
at org.hibernate.cfg.annotations.SimpleValueBinder.make(SimpleValueBinder.java:407)
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyAndValue(PropertyBinder.java:187)
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:199)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2225)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:911)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:738)
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 19 common frames omitted
What am I doing wrong? Thanks in advance.
You are trying to reference the Empolyee three times from the EmployeeDocument but only one of those is by primary key. The other two are referenced by non-primary key columns and you would need to use the referencedColumnName option additionally to make this work:
#JsonIgnore
#ManyToOne
#JoinColumn(name = "employee_id", nullable = false)
public Employee employee;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "created_by", referencedColumnName="created_by", updatable = false)
#JsonBackReference
public Employee createdBy;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "updated_by". , referencedColumnName="updated_by")
#JsonBackReference
public Employee updatedBy;

Saving Record in Relation Spring Boot

I am creating a project in spring boot which creates record by api call.
so I have two table ( name and phone ) below is my domain:
#Entity
#Table(name = "name")
public class Name {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "active", nullable = false)
private boolean active = true;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(mappedBy = "name")
#JsonIgnoreProperties("name")
private List<Phone> phones;
}
And
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "number", nullable = false)
private String number;
#Column(name = "active", nullable = false)
private boolean active = true;
#ManyToOne(targetEntity= Name.class)
#JoinColumn(name="name_id"))
private Name name;
}
The Code to create the name is as follows:
public Name createNewName(Name createName) {
Name newName = new Name();
newName = NameRepo.save(createName);
return newName;
}
And Repository is:
#Repository
public interface NameRepository extends PagingAndSortingRepository<Name, Long> {}
So My problem is when i send a request using api to call this, Name does not store Phone values and also does not link if exist.
My request is as follows:
{
"name": "testrretf",
"active": true,
"phones":[{
"id":1
}]
}
This request should link the new Name to existing Phone id=1
And
{
"name": "testrretf",
"active": true,
"phones":[{
"number":"Test Phone",
"active":true,
}]
}
This request should create a Phone and link to the created Name.
Please help me..
Thanks,
UPDATE# Below is the Create Table Query:
CREATE TABLE `name` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`active` bit(1) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `IDX_NAME` (`name `),
KEY `IDX_NAME_ACTIVE` (`active`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
CREATE TABLE `phone` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`active` bit(1) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`name_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_PHONE_ACTIVE` (`active`),
KEY `fk_name_phone` (`name_id`),
CONSTRAINT `fk_name_phone` FOREIGN KEY (`name_id`) REFERENCES `name` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

Using RowMapper and JdbcTemplate got NullPointerException

I have two entities - user and accessgroup. When getting user entity from MySQL database using RowMapper in JdbcTemplate I have NullPointerException. When not using setter for accessgroup in UserRowMapper I dont have NPE but have null in AccessGroup accessGroup.
Table
CREATE TABLE `users` (
`USER_ID` int(11) NOT NULL AUTO_INCREMENT,
`USER_EMAIL` varchar(255) DEFAULT NULL,
`USER_NAME` varchar(255) DEFAULT NULL,
`USER_PWD` varchar(255) DEFAULT NULL,
`ACCESSGROUP_GROUP_ID` int(11) DEFAULT NULL,
PRIMARY KEY (`USER_ID`),
KEY `FK_users_ACCESSGROUP_GROUP_ID` (`ACCESSGROUP_GROUP_ID`),
CONSTRAINT `FK_users_ACCESSGROUP_GROUP_ID` FOREIGN KEY (`ACCESSGROUP_GROUP_ID`) REFERENCES `access_group` (`GROUP_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
CREATE TABLE `access_group` (
`GROUP_ID` int(11) NOT NULL AUTO_INCREMENT,
`GROUP_NAME` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`GROUP_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
Entities
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "USER_ID")
private Integer userId;
#Column(name = "USER_EMAIL")
private String userEmail;
#Column(name = "USER_NAME")
private String userName;
#Column(name = "USER_PWD")
private String userPwd;
#JoinColumn(name = "ACCESSGROUP_GROUP_ID", referencedColumnName = "GROUP_ID")
#ManyToOne
private AccessGroup accessGroup;
#Entity
#Table(name = "access_group")
public class AccessGroup implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "GROUP_ID")
private Integer groupId;
#Basic(optional = false)
#Column(name = "GROUP_NAME")
private String groupName;
#OneToMany(mappedBy = "accessGroup")
private Set users;
Dao
#Repository("userDao")
public class UserDaoImpl implements IUserDao {
#Autowired
private JdbcTemplate jdbcTemplate;
#Value("${sql.user.get.email.pwd}")
private String getByEmailAndPwd;
//sql.user.get.email.pwd=SELECT * FROM users WHERE user_email = ? AND user_pwd = ?
#Transactional
#Override
public User getUserByEmailAndPwd(String email, String password) {
return jdbcTemplate.queryForObject(getByEmailAndPwd, new Object[]{email, password}, new UserRowMapper());
}
#Repository("accessGroupDao")
public class AccessGroupDaoImpl implements IAccessGroupDao {
private JdbcTemplate jdbcTemplate;
#Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Value("${sql.accessgroup.get.id}")
private String getAccessGroupById;
//sql.accessgroup.get.id=SELECT * FROM access_group WHERE GROUP_ID = ?
#Transactional
#Override
public AccessGroup getGroupById(int id) {
return jdbcTemplate.queryForObject(getAccessGroupById, new Object[]{id}, new AccessGroupRowMapper());
}
RowMappers
#Component
public class UserRowMapper implements RowMapper {
private AccessGroupService accessGroupService;
#Autowired
public void setAccessGroupService(AccessGroupService accessGroupService) {
this.accessGroupService = accessGroupService;
}
#Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setId(resultSet.getInt("USER_ID"));
user.setEmail(resultSet.getString("USER_EMAIL"));
user.setName(resultSet.getString("USER_NAME"));
user.setpwd(resultSet.getString("USER_PWD"));
//when adding here user.setAccessGroup(accessGroupService.getGroupById(resultSet.getInt("ACCESSGROUP_GROUP_ID"))); I have NPE
return user;
}
public class AccessGroupRowMapper implements RowMapper {
#Override
public AccessGroup mapRow(ResultSet resultSet, int i) throws SQLException {
AccessGroup accessGroup = new AccessGroup();
accessGroup.setId(resultSet.getInt("GROUP_ID"));
accessGroup.setName(resultSet.getString("GROUP_NAME"));
return accessGroup;
}
}
1) Add the following property to your #Entity class 'User' & generate the getter & setter methods:
#Transient
private Integer userIdTransientField;
#Transient means the property will not be stored in the database
2) Modify RowMapper class:
Replace this line with the following :
user.setId(resultSet.getInt("USER_ID")); -> user.setUserIdTransientField(resultSet.getInt("USER_ID"));
3) When you refer to a 'User' object and you want to do a Update/Delete for jdbcTemplate or simply want to get the Id value then use the getUserIdTransientField method.

org.hibernate.AnnotationException: A Foreign key refering X from Y has the wrong number of column. should be 2

Can anyone help me with this and tell me what I'm missing. Have gone through a number of examples and seem to have everything configured correctly but I keep getting this exception:
org.hibernate.AnnotationException: A Foreign key refering com.bank.entity.Customer from com.bank.entity.Account has the wrong number of column. should be 2
I have a class called Branch that has 1:M relationship with Customer. Customer in turn has a 1:M relationship with Account.
Note: Customer also has an embeddable Address class
Here is my code:
Branch Class
#Entity
#Table(name = "Branch")
public class Branch extends AbstractPersistable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "branch_Name")
private String branchName;
#OneToMany(mappedBy = "branch")
private Set<Customer> customers;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Embeddable Address Class
#Embeddable
public class Address {
#Column(name = "houseNumber", nullable = false)
private String houseNumber;
#Column(name = "streetName", nullable = false)
private String streetName;
#Column(name = "city", nullable = false)
private String city;
#Column(name = "country", nullable = false)
private String country;
#Column(name = "eirCode", nullable = false)
private String eirCode;
}
Customer Class
#Entity
#Table(name = "Customer")
public class Customer extends AbstractPersistable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "first_Name")
private String firstName;
#Column(name = "surname")
private String surName;
#Embedded
Address address;
#ManyToOne
#JoinColumn(name = "branchId", nullable = false)
private Branch branch;
#OneToMany(mappedBy = "customer")
private Set<Account> accounts;
}
Account Class
#Entity
#Table(name = "Account")
public class Account extends AbstractPersistable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "account_type")
private String type;
#Column(name = "interest_rate")
private double rate;
#Column(name = "account_balance")
private double balance;
#ManyToOne
#JoinColumn(name = "customerId", nullable = false)
private Customer customer;
}
Here I create the tables
CREATE TABLE IF NOT EXISTS `Branch` (
`id` BIGINT(10) NOT NULL AUTO_INCREMENT,
`branch_Name` VARCHAR(25) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `Customer` (
`id` BIGINT(10) NOT NULL AUTO_INCREMENT,
`first_Name` VARCHAR(25) NOT NULL,
`surname` VARCHAR(25) NOT NULL,
`houseNumber` VARCHAR(25) NOT NULL,
`streetName` VARCHAR(120) NOT NULL,
`city` VARCHAR(25) NOT NULL,
`country` VARCHAR(25) NOT NULL,
`eirCode` VARCHAR(25) NOT NULL,
`branchId` BIGINT(10) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_CUST_BRANCH` (`branchId`),
CONSTRAINT `FK_CUST_BRANCH` FOREIGN KEY (`branchId`) REFERENCES `Branch` (`id`)
);
CREATE TABLE IF NOT EXISTS `Account` (
`id` BIGINT(10) NOT NULL AUTO_INCREMENT,
`account_type` VARCHAR(25) NOT NULL,
`interest_rate` DOUBLE NOT NULL,
`account_balance` DOUBLE NOT NULL,
`customerId` BIGINT(10) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_CUST_ACC` (`customerId`),
CONSTRAINT `FK_CUST_ACC` FOREIGN KEY (`customerId`) REFERENCES `Customer` (`id`)
);
In Account you are saying :
#ManyToOne
#JoinColumn(name = "customerId", nullable = false)
private Customer customer;
But there is not column with name customerId(?) so you should give name to primary key of Customer
try changing this in Customer
#Entity
#Table(name = "Customer")
public class Customer extends AbstractPersistable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="customerId")
private Long id;
...
}

Categories