Hibernate database relation annotations - java

I've been struggling with this for so long now. I have a database with two tables "product" and "categories"
CREATE TABLE `product` (
`idproduct` int NOT NULL AUTO_INCREMENT,
`idcategory` int DEFAULT NULL,
`product_name` varchar(255) DEFAULT NULL,
`product_category` varchar(255) DEFAULT NULL,
`product_description` varchar(255) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`idproduct`),
KEY `fkcat` (`idcategory`),
CONSTRAINT `fkcat` FOREIGN KEY (`idcategory`) REFERENCES `categories` (`idcategory`)
) ENGINE=InnoDB AUTO_INCREMENT=149 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
CREATE TABLE `categories` (
`idcategory` int NOT NULL AUTO_INCREMENT,
`category_name` varchar(255) NOT NULL,
`category_description` varchar(255) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`idcategory`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Now I'm trying to get a hibernate join query so I can retrieve let's say
product_name and category_name
One product belongs only to one category (for example, if the product is "black t-shirt", its value for the column "idcategory" would be 2. This is enforced by the foreign key.
The table categories entries can be associated with more than one product (for example, "category_name" = 2 can be associated with many products.
How can this design be implemented in hibernate entities? I've tried this but isn't working...
#Entity
#Table(name = "product")
public class Product implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idproduct")
private int idproduct;
#Column(name = "idcategory")
private int idcategory;
#Column(name = "product_name")
private String productName;
#Column(name = "product_description")
private String productdescription;
#Column(name = "product_category")
private String productcategory;
#OneToMany(targetEntity = Categories.class, cascade = CascadeType.ALL)
#JoinColumn(name = "idcategory",referencedColumnName="idcategory")
private List<Categories> category;
#Entity
#Table(name = "categories")
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idcategory")
private int idcategory;
#Column(name = "category_name")
private String category_name;
#Column(name = "category_description")
private String category_description;
and the query is
SELECT p, c FROM Product p INNER JOIN p.category c

this is not correct
#OneToMany(targetEntity = Categories.class, cascade = CascadeType.ALL)
#JoinColumn(name = "idcategory",referencedColumnName="idcategory")
private List<Categories> category;
Product can't have many categories... it is actually the reverse ->
#Entity
#Table(name = "categories")
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idcategory")
private int idcategory;
#Column(name = "category_name")
private String category_name;
#Column(name = "category_description")
private String category_description;
#OneToMany(cascade = CascadeType.ALL, mappedBy="category")
private List<Product> products;
and Product
#Entity
#Table(name = "product")
public class Product implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idproduct")
private int idproduct;
#Column(name = "idcategory")
private int idcategory;
#Column(name = "product_name")
private String productName;
#Column(name = "product_description")
private String productdescription;
#Column(name = "product_category")
private String productcategory;
#ManyToOne
private Categories categories;
Suggestion : rename Categories to Category

Related

Spring creating own columns with wrong reference in table

I have problem with "communication" between Spring and PostgreSQL.
My class User.java:
public static final String TABLE_NAME = "USERS";
public static final String SEQENCE = "USERS_SEQ";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long userId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "department_id")
private Department department;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organizazion_id")
private Organization organization;
Create table script for USERS:
CREATE TABLE IF NOT EXISTS USERS (
USER_ID BIGINT NOT NULL,
DEPARTMENT_ID BIGINT,
ORGANIZATION_ID BIGINT,
PRIMARY KEY (USER_ID),
FOREIGN KEY (DEPARTMENT_ID) REFERENCES DEPARTMENT(DEPARTMENT_ID),
FOREIGN KEY (ORGANIZATION_ID) REFERENCES ORGANIZATION(ORGANIZATION_ID)
);
Class Department.java
public static final String TABLE_NAME = "DEPARTMENT";
public static final String SEQENCE = "DEPARTMENT_SEQ";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long departmentId;
private String departmentName;
.
.
. //Some other columns of primitive types about department..
Create table script for DEPARTMENT:
CREATE TABLE IF NOT EXISTS DEPARTMENT (
DEPARTMENT_ID BIGINT NOT NULL,
DEPARTMENT_NAME VARCHAR(50),
PRIMARY KEY (DEPARTMENT_ID)
);
Class Organization.java
public static final String TABLE_NAME = "ORGANIZATION";
public static final String SEQENCE = "ORGANIZATION_SEQ";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long organizationId;
private String organizationName;
private String street;
private String postalCode;
private String state;
private String city;
Create table script for ORGANIZATION:
CREATE TABLE IF NOT EXISTS ORGANIZATION (
ORGANIZATION_ID BIGINT NOT NULL,
ORGANIZATION_NAME VARCHAR(50),
STREET VARCHAR(255),
POSTAL_CODE VARCHAR(50),
STATE VARCHAR(255),
CITY VARCHAR(255),
PRIMARY KEY (ORGANIZATION_ID)
);
When I run the program, the Spring create "own" columns in PostgreSQL, and it's look like:
USER_ID, DEPARTMENT_ID, ORGANIZATION_ID, DEPARTMENT_DEPARTMENT_ID, ORGANIZATION_ORGANIZATION_ID
How can I fix it ? It should be without columns
DEPARTMENT_DEPARTMENT_ID, ORGANIZATION_ORGANIZATION_ID
The annotation #Column(name = "column_name") can't be used here.
As join column you should reference the attribute in the other class:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long userId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "departmentId")
private Department department;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organizazionId")
private Organization organization;

sql constraint violation exception

I have an entity Mathematics referenced by MathematicsAnswer. If a perform a post request on Mathematics, I get the exception that field on MathsAnswer cannot be null. But I actually did cascade on the field. Please I need solution this.
java.sql.SQLIntegrityConstraintViolationException: Column 'question_id' cannot be null
sql schema:
CREATE TABLE MATHEMATICS(
id integer not null auto_increment,
year date not null,
question_no int not null,
question varchar(128) default null,
primary key(id)
) engine=InnoDb;
CREATE TABLE MATHS_ANSWER(
id integer not null auto_increment,
date date default null,
question_no int not null,
question_id int not null,
solution varchar(128) default null,
solution_url varchar(128) default null,
primary key(id),
foreign key(question_id) references MATHEMATICS(id) ON DELETE NO ACTION ON UPDATE NO ACTION
) engine = InnoDb;
entity class:
#Entity
#Table(name = "Mathematics")
public class Mathematics {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
#Column(name = "year")
private Date year;
#Column(name = "question_no")
private Integer questionNo;
#Column(name = "question")
private String question;
#OneToOne(mappedBy = "maths", fetch = FetchType.EAGER,cascade = CascadeType.ALL
)
private MathsAnswers answers = new MathsAnswers();//getters & setters
MathsAnswers.java:
#Entity
#Table(name = "Mathematics")
public class Mathematics {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
#Column(name = "year")
private Date year;
#Column(name = "question_no")
private Integer questionNo;
#Column(name = "question")
private String question;
#OneToOne(mappedBy = "maths", fetch = FetchType.EAGER,cascade = CascadeType.ALL
)
private MathsAnswers answers = new MathsAnswers();//getters & setters
jpaRepo:
#RepositoryRestResource(collectionResourceRel = "mathematics", path = "maths")
public interface MathsRepo extends JpaRepository<Mathematics, Integer> {
}
post request:
{
"year":"2004-01-03",
"questionNo":"4",
"question":"How many weeks makes a year?"
}
The table name specified for my MathsAnswer entity was wrong; should've been Mathsanswer instead of Mathematics.

How to create two entities and relate them

First of all, apologize for the grammatical errors that you can make. My English is not very good.
I'm trying to create dinamically an Entity and relathion with other Entity.
The idea is send a json file and get some properties to create that Entity, later associate that entity with the other. However, I can't because throw Exception like:
attempted to assign id from null one-to-one property
So, here in my SchemeService I try to create both entities:
protected Scheme createScheme(final String creatorId, final String name, final String description, final InputStream inputStream) {
DeserializeJSONFile desJsonFile = new DeserializeJSONFile();
desJsonFile.init(inputStream);
TableEntity table = new TableEntity();
table.setCreator(creatorId);
table.setProperties(desJsonFile.getProperties().toString());
table.setGeometry(desJsonFile.getGeometry().toString());
createTable(table);
Scheme scheme = new Scheme();
scheme.setCreator(creatorId);
scheme.setName(name);
scheme.setDescription(description);
scheme.setTable(table);
createScheme(scheme);
return scheme;
}
private void createTable(final TableEntity table) {
tableDao.create(table);
}
protected void createScheme(final Scheme scheme) {
schemeDao.create(scheme);
}
Here is my TableEntity:
public class TableEntity extends BaseEntityActivable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SCHEME_SEQ_GEN")
#SequenceGenerator(name = "SCHEME_SEQ_GEN", sequenceName = "test_seq_table", allocationSize = 1)
#Column(name = "table_id")
private Long tableId;
#Type(type= "jsonb")
#Column(name = "properties", columnDefinition = "json")
private String properties;
#Type(type= "jsonb")
#Column(name = "geometry", columnDefinition = "json")
private String geometry;
#OneToOne
#MapsId
private Scheme scheme;
}
Here is my SchemeEntity:
public class Scheme extends BaseEntityActivable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SCHEME_SEQ_GEN")
#SequenceGenerator(name = "SCHEME_SEQ_GEN", sequenceName = "test_seq_scheme", allocationSize = 1)
#Column(name = "scheme_id")
private Long schemeId;
#Column(name = "name", nullable = false)
#NotEmpty(message = AxisMapsErrorConstants.NAME_CANT_BE_EMPTY)
private String name;
#Column(name = "description")
private String description;
#OneToOne(mappedBy = "scheme", cascade = CascadeType.ALL)
#JoinColumn(name = "scheme_id", referencedColumnName = "table_id", foreignKey = #ForeignKey(name = "fk_scheme_table_1"))
private TableEntity table;
}
Here is my sql:
create sequence test_seq_table start 1 increment 1;
create sequence test_seq_scheme start 1 increment 1;
create table maps_table (
table_id int8 not null,
created_at timestamp not null,
created_by varchar(255),
updated_at timestamp,
updated_by varchar(255),
is_active boolean not null,
properties jsonb not null,
geometry jsonb not null,
primary key (table_id)
);
create table maps_scheme (
scheme_id int8 not null,
created_at timestamp not null,
created_by varchar(255),
updated_at timestamp,
updated_by varchar(255),
is_active boolean not null,
description varchar(255),
name varchar(255) not null,
table_id int8 not null,
primary key (scheme_id)
);
alter table maps_scheme
add constraint fk_scheme_table_1
foreign key (scheme_id)
references maps_table;
since you are using #mapsId this means you are using the same identifier in your relation with scheme, which means first the scheme should not be nullable and it should be available as managed entity each time your object is flushed, which also means that you can do the persistence only from one side of the relation since the id of scheme should be available when persisting your entity.
I am not sure if you really need #mapsId here, since you already have a bidirectional relation which means anyway you will be able to access both sides of your entity.
I would suggest to remove #mapsId here.
Thanks everyone for helping me.
This is my solution.
Scheme:
public class Scheme extends BaseEntityActivable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SCHEME_SEQ_GEN")
#SequenceGenerator(name = "SCHEME_SEQ_GEN", sequenceName = "aguas_seq_scheme", allocationSize = 1)
#Column(name = "scheme_id")
private Long schemeId;
#Column(name = "name", nullable = false)
#NotEmpty(message = AxisMapsErrorConstants.NAME_CANT_BE_EMPTY)
private String name;
#Column(name = "description")
private String description;
#OneToOne(cascade= { CascadeType.ALL }, fetch = FetchType.LAZY)
#JoinColumn(name="table_id")
private TableEntity table;
}
TableEntity:
public class TableEntity extends BaseEntityActivable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SCHEME_SEQ_GEN")
#SequenceGenerator(name = "SCHEME_SEQ_GEN", sequenceName = "aguas_seq_table", allocationSize = 1)
#Column(name = "table_id")
private Long tableId;
#Type(type= "jsonb")
#Column(name = "properties", columnDefinition = "json")
private String properties;
#Type(type= "jsonb")
#Column(name = "geometry", columnDefinition = "json")
private String geometry;
#OneToOne(mappedBy= "table")
private Scheme scheme;
}
SQL:
create sequence aguas_seq_table start 1 increment 1;
create sequence aguas_seq_scheme start 1 increment 1;
create table maps_table (
table_id int8 not null,
created_at timestamp not null,
created_by varchar(255),
updated_at timestamp,
updated_by varchar(255),
is_active boolean not null,
properties jsonb not null,
geometry jsonb not null,
primary key (table_id)
);
create table maps_scheme (
scheme_id int8 not null,
created_at timestamp not null,
created_by varchar(255),
updated_at timestamp,
updated_by varchar(255),
is_active boolean not null,
description varchar(255),
name varchar(255) not null,
table_id int8 not null,
primary key (scheme_id)
);
SchemeService to create scheme and table:
protected Scheme createScheme(final String creatorId, final String name, final String description, final InputStream inputStream) {
DeserializeJSONFile desJsonFile = new DeserializeJSONFile();
desJsonFile.init(inputStream);
TableEntity table = new TableEntity();
table.setCreator(creatorId);
table.setGeometry(desJsonFile.loadGeometries().toString());
table.setProperties(desJsonFile.loadProperties().toString());
createTable(table);
Scheme scheme = new Scheme();
scheme.setCreator(creatorId);
scheme.setName(name);
scheme.setDescription(description);
scheme.setTable(table);
createScheme(scheme);
return scheme;
}

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;

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