I have two class:
Order.java:
#Entity
#Table(name = "orders", catalog = "ownDB")
public class Order {
private int orderNO;
private String oderName;
private Set<Room> rooms = new HashSet<Room>(0);
public Order(int orderNo, String orderName, Set<Room> rooms) {
this.oderNo = orderNo;
this.orderName = orderName;
this.rooms = rooms;
}
#Id
#Column(name = "orderNO", unique = true, nullable = false, length = 6)
public int getOrderNO() {
return this.orderNO;
}
public void setOrderNo(int OrderNO) {
this.orderNO = orderNO;
}
#Column(name = "orderName", nullable = false, length = 100)
public String getOrderName() {
return this.orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "rooms_orders", joinColumns = { #JoinColumn(name = "orderNO") }, inverseJoinColumns = { #JoinColumn(name = "roomNO") })
public Set<Room> getRoom() {
return this.rooms;
}
public void setRoom(Set<Room> rooms) {
this.rooms = rooms;
}
}
And this is the room.java:
#Entity
#Table(name = "rooms", catalog = "ownDB")
public class {
private int roomNO;
private String name;
private Set<Order> orders = new HashSet<Order>(0);
public Room(int roomNO, String name, Set<Order> orders) {
this.roomNO = roomNO;
this.name = name;
this.orders = orders;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "roomNO", unique = true, nullable = false, length = 6)
public int getRoomNO() {
return this.roomNO;
}
public void setRoomNO(int roomNO) {
this.roomNO = roomNO;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "rooms_orders", joinColumns = { #JoinColumn(name = "roomNO") }, inverseJoinColumns = { #JoinColumn(name = "orderNO") })
public Set<Order> getOrders() {
return this.orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
SQL:
CREATE TABLE rooms (
roomNO int(6) NOT NULL ,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY (roomNO));
CREATE TABLE orders (
orderNO int(6) NOT NULL AUTO_INCREMENT,
orderName VARCHAR(100) NOT NULL,
PRIMARY KEY (orderNO));
CREATE TABLE rooms_orders (
roomNO int(6) NOT NULL,
orderNO int (6) NOT NULL,
PRIMARY KEY (roomNO, orderNO));
What is the problem with the two mapping? It is works for me. But I don't want to use, if it isn't the right way. If I am change the second mapping to "#ManyToMany(mappedBy="room")" (without the joinTable annotation) in the Order class. I can't list all rooms (with their orders), because I got this error message:
"Failed to lazily initialize a collection of role: com.room.model.Room.orders, could not initialize proxy - no Session"
What is the right way to can list all orders with their rooms and all rooms with their orders. So I need "two-way" join.
There are many errors in the code you posted.
First of all, your join table is not correctly defined. It shouldn't have a seperate column for the ID: noone will ever populate this column. It should be defined as
CREATE TABLE rooms_orders (
roomNO int(6) NOT NULL,
orderNO int (6) NOT NULL,
PRIMARY KEY (rommNO, orderNO));
Second, your mapping is wrong. A bidirectional association always has an owner side, which defines how the association is mapped, and an inverse side, which uses the mappedBy attribute to tell JPA that this is the inverse side, and where to find the owner side. So, in Room, the association should be mapped with
#ManyToMany(mappedBy = "rooms")
public Set<Order> getOrders() {
return this.orders;
}
And finally, your mapping for the association doesn't match with the column names in your table:
#JoinTable(name = "rooms_orders",
joinColumns = { #JoinColumn(name = "orderNO") },
inverseJoinColumns = { #JoinColumn(name = "roomNumber") })
There is no column "roomNumber" in the table. The column is named "roomNO".
Related
OneToOne mapping not working: EntityA.entityB referencing EntityB not mapped to a single property
I have two entities, EntityA and EntityB.
EntityA has a composite primary key on two fields: id and flag.
EntityB also has a composite primary key on two fields: id and flag.
The two entities are linked with a common field / column: entityBKey. (This is a foreign key but not explicitly defined as such at the database level, if that makes a difference. Old design can't really change much)
This is how I am calling EntityA:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<EntityA> criteriaQuery = builder.createQuery(EntityA.class);
Root<EntityA> from = criteriaQuery.from(EntityA.class);
criteriaQuery.select(from);
But I get this error on application boot:
EntityA.entityB referencing EntityB not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:203)
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:104)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1750)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1694)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:86)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:479)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:746)
In some places I have read it says that non-primary keys can be referenced by using the referencedColumnName attribute but it is clearly not working.
Any ideas what I can do here? Much appreciated.
EntityA:
#Entity
#Table(name = "EntityA")
#IdClass(KeyClass.class)
public class EntityA implements Serializable {
#Id
#Column(name = "id", nullable = false)
protected Integer id = null;
#Id
#Column(name = "flag", nullable = false)
protected Integer flag = null;
#Column(name = "EntityAKey", nullable = false)
private String entityAKey = null;
#Column(name = "EntityBKey", nullable = false)
private String entityBKey = null;
#OneToOne(mappedBy="entityA")
private EntityB entityB;
public EntityA() {
super();
}
}
EntityB:
#Entity
#Table(name = "EntityB")
#IdClass(KeyClass.class)
public class EntityB implements Serializable {
#Id
#Column(name = "id", nullable = false)
protected Integer id = null;
#Id
#Column(name = "flag", nullable = false)
protected Integer flag = null;
#Column(name = "EntityBKey", nullable = false)
private String entityBKey = null;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "entityBKey", referencedColumnName = "entityBKey", insertable = false, updatable = false),
#JoinColumn(name = "flag", referencedColumnName = "flag", insertable = false, updatable = false)}
)
#Where(clause = "flag=1")
private EntityA entityA;
public EntityB() {
super();
}
}
KeyClass:
public class KeyClass implements Serializable {
private Integer id = null;
private Integer flag = null;
public KeyClass() {
}
public KeyClass(Integer id, Integer flag) {
this.id = id;
this.flag = flag;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getFlag() {
return flag;
}
public void setFlag(Integer flag) {
this.flag = flag;
}
#Override
public boolean equals(Object o) {
...
}
#Override
public int hashCode() {
...
}
}
I have a little problem to understand how it make sense to insert a List of languages in JPA for a Oracle 19 DB.
The API receives a DTO with a list of chosen languages for one user.
{
"userId": 173125,
"logname": "testor2",
"lastname": "Testimator2",
"firstname": "Testor2",
"selectedLang": [
"German",
"English"
],
}
The Table looks like this for User and had a Table with pk and fk for user and language code.
The Table should remove unused languages that not in the received DTO || insert new languages in the table that not exist.
Tables that used in the db are:
USER
Columnname
Type
keys
USERID
int
PK
LOGNAME
row
-
NAME
varchar
-
LASTNAME
varchar
-
USERLANGUAGE
Columnname
Type
keys
USERLANGUAGEID
int
PK --part of primary key
USERID
int
PK --part of primary key
Languagecode
varchar
-
Now the tricky part. I want to store the languages as a List and have thought that jpa deals with the update, remove or inserts itself.
#Entity
#Table(name = "user", schema = "test")
public class UserEntity {
#Id
#Column(name = "USERID", nullable = false)
private long userid;
#Column(name = "LOGNAME", nullable = false, length = 50)
private String logname;
#Column(name = "NAME", nullable = false, length = 60)
private String name;
#Column(name = "LASTNAME", nullable = false, length = 80)
private String lastname;
#OneToMany(mappedBy = "userid", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UserlanguageEntity> languages;
public List<UserlanguageEntity> getLanguages() {
return languages;
}
public void setLanguages(List<UserlanguageEntity> languages) {
this.languages = languages;
}
public UserEntity addLanguage(UserlanguageEntity userlanguageEntity) {
languages.add(userlanguageEntity);
userlanguageEntity.setUserid(this);
return this;
}
public UserEntity removeLanguage(UserlanguageEntity userlanguageEntity) {
languages.remove(userlanguageEntity);
userlanguageEntity.setUserid(null);
return this;
}
}
UserLanguageEntity
#Entity
#Table(name = "USRLANGUAGE")
public class UsrlanguageEntity {
#EmbeddedId
private UserId user;
private String languagecode;
#Basic
#Column(name = "LANGUAGECODE", nullable = true, length = 4)
public String getLanguagecode() {
return languagecode;
}
public void setLanguagecode(String languagecode) {
this.languagecode = languagecode;
}
public UserId getUser() {
return user;
}
public void setUser(UserId user) {
this.user = user;
}
...
}
Embedded ID
#Embeddable
public class UserId implements Serializable {
#SequenceGenerator(name = "userlanguageid", sequenceName =
"USERLANGUAGEID", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
"userlanguageid")
#Column(name = "USERLANGUAGEID", nullable = false, precision = 0)
private long userlanguageid;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USERID")
private UserEntity userid;
...
}
So the fetch method is fine and works as intended, but when i want to update the languages I get errors.
First of all get the list out of db to an UserEntity, then want to clear the UserLanguageEntitylist -> the list in the UserEntity. And than add the received list, maybe thats imposible. So what would be the best implementation to get this to work. First i want to delete all languagecodes in the db and write the new list into it, but it feels a bit dirty to me because maybe some have not to be changed.
public void setUserDataForCompany(UserDto userDto) {
CompanyEntity companyEntity = companyRepository.findById(41).orElseThrow(
NoSuchElementException::new);
UserEntity userEntity = userRepository.findById(userDto.getUserId()).orElseThrow(
NoSuchElementException::new);
companyUserDataMapper.toEntity(userDto, companyEntity, userEntity);
setLanguagesForUser(userDto, userEntity);
userRepository.save(userEntity);
}
// Here i have no clue to update existing or store missing languages
private void setLanguagesForUser(UserDto userDto, UserEntity userEntity) {
userDto.getSelectedLang().forEach(language -> {
UserlanguageEntity userlanguageEntity = new UserlanguageEntity();
userlanguageEntity.setLanguagecode(language.getLngCode());
userEntity.addLanguage(userlanguageEntity);
});
}
Could someone get me a hint to doing it the right way?
Thanks a lot and cheers
Can someone help me with a simple explanation of how to use #Embeddable ?
I have this situation below!
One company, has several employees, and my employee table has 2 ID fields (register_number and name)
Is this the right approach?
#Entity
#Table(name = "COMPANY")
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private Employee employeeId;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
#Column(name = "ID", unique = true, nullable = false, precision = 38)
private Long id;
#Column(name = "NAME", nullable = false, length = 50)
private String name;
#ToString.Exclude
#EqualsAndHashCode.Exclude
#OneToMany(fetch = FetchType.LAZY, mappedBy = "registerNumber")
private Set<Employee> employees;
}
//
#Embeddable
#Entity
#Table(name = "EMPLOYEE")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "REGISTER_NUMBER", nullable = false, length = 100)
private String registerNumber;
#Column(name = "NAME", nullable = false, length = 50)
private String name;
#Column(name = "EMAIL", nullable = false, length = 50)
private String email;
}
I think you are looking a way to support composite key using hibernate. You should move those fields to a new class and annotate that class with #Embeddable.
For classes mentioned in the question, create a new Embeddable class EmployeeIdClass with the fields (registerNumber and name), and have a variable for this class's object in Employee, annotate it with #EmbeddedId.
EmployeeIdClass
#Embeddable
public class EmployeeIdClass implements Serializable{
#Column(name = "REGISTER_NUMBER", nullable = false, length = 100)
private String registerNumber;
#Column(name = "NAME", nullable = false, length = 50)
private String name;
public String getRegisterNumber() {
return registerNumber;
}
public void setRegisterNumber(String registerNumber) {
this.registerNumber = registerNumber;
}
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;
EmployeeIdClass that = (EmployeeIdClass) o;
return Objects.equals(registerNumber, that.registerNumber) &&
Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(registerNumber, name);
}
}
Employee
#Entity
#Table(name = "EMPLOYEE")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
#Column(name = "employeeId", nullable = false, length = 50)
private EmployeeIdClass employeeId;
#Column(name = "EMAIL", nullable = false, length = 50)
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public EmployeeIdClass getEmployeeId() {
return employeeId;
}
public void setEmployeeId(EmployeeIdClass employeeId) {
this.employeeId = employeeId;
}
}
Company
#Entity
#Table(name = "COMPANY")
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
// #EmbeddedId
// private Employee employeeId;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
#Column(name = "ID", unique = true, nullable = false, precision = 38)
private Long id;
#Column(name = "NAME", nullable = false, length = 50)
private String name;
// #ToString.Exclude
// #EqualsAndHashCode.Exclude
#OneToMany(fetch = FetchType.LAZY)
private Set<Employee> employees;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
CompanyEmployeeTest
public class CompanyEmployeeTest {
public static void main(String[] args) {
EmployeeIdClass employeeIdClass2 = new EmployeeIdClass();
employeeIdClass2.setName("b");
employeeIdClass2.setRegisterNumber("2");
EmployeeIdClass employeeIdClass3 = new EmployeeIdClass();
employeeIdClass3.setName("c");
employeeIdClass3.setRegisterNumber("3");
Employee emp2 = new Employee();
emp2.setEmail("b#");
Employee emp3 = new Employee();
emp3.setEmail("c#");
emp2.setEmployeeId(employeeIdClass2);
emp3.setEmployeeId(employeeIdClass3);
Company company = new Company();
Set<Employee> set = new HashSet<>();
set.add(emp2);
set.add(emp3);
company.setEmployees(set);
company.setName("first-company");
company.setId(1234l);
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(company);
session.save(emp3);
session.save(emp2);
transaction.commit();
session.close();
}
}
Queries ran by Hibernate
Hibernate: create table COMPANY (ID bigint not null auto_increment, NAME varchar(50) not null, primary key (ID)) engine=MyISAM
Hibernate: create table COMPANY_EMPLOYEE (Company_ID bigint not null, employees_NAME varchar(50) not null, employees_REGISTER_NUMBER varchar(100) not null, primary key (Company_ID, employees_NAME, employees_REGISTER_NUMBER)) engine=MyISAM
Hibernate: create table EMPLOYEE (NAME varchar(50) not null, REGISTER_NUMBER varchar(100) not null, EMAIL varchar(50) not null, primary key (NAME, REGISTER_NUMBER)) engine=MyISAM
Hibernate: alter table COMPANY_EMPLOYEE add constraint UK_lnmh1scqoa65gxcryjyeroyj unique (employees_NAME, employees_REGISTER_NUMBER)
Hibernate: alter table COMPANY_EMPLOYEE add constraint FKkkjhj0prbvia5yiqebnefkkb5 foreign key (employees_NAME, employees_REGISTER_NUMBER) references EMPLOYEE (NAME, REGISTER_NUMBER)
Hibernate: alter table COMPANY_EMPLOYEE add constraint FKivik2ern4s4074u9eb3c6u7jw foreign key (Company_ID) references COMPANY (ID)
Hibernate: insert into COMPANY (NAME) values (?)
Hibernate: insert into EMPLOYEE (EMAIL, NAME, REGISTER_NUMBER) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (EMAIL, NAME, REGISTER_NUMBER) values (?, ?, ?)
Hibernate: insert into COMPANY_EMPLOYEE (Company_ID, employees_NAME, employees_REGISTER_NUMBER) values (?, ?, ?)
Hibernate: insert into COMPANY_EMPLOYEE (Company_ID, employees_NAME, employees_REGISTER_NUMBER) values (?, ?, ?)
I am really stuck in solving the below error. Please help me to make it solve ?
I'm developing ManyToMany relationship example.
Initial SessionFactory creation failed.org.hibernate.MappingException: Foreign key (FK302BCFEEB260666:category [CATEGORY_ID])) must have same number of columns as the referenced primary key (category [STOCK_ID,CATEGORY_ID])
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.mkyong.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:17)
at com.mkyong.util.HibernateUtil.<clinit>(HibernateUtil.java:8)
at com.mkyong.App.main(App.java:13)
Caused by: org.hibernate.MappingException: Foreign key (FK302BCFEEB260666:category [CATEGORY_ID])) must have same number of columns as the referenced primary key (category [STOCK_ID,CATEGORY_ID])
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:112)
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:95)
at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1808)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1729)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1396)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1829)
at com.mkyong.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
... 2 more
The code I developed,
Category.java
#Entity
#Table(name = "category")
public class Category implements java.io.Serializable {
private static final long serialVersionUID = 8833944947723156024L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "CATEGORY_ID", unique = true, nullable = false)
private Integer categoryId;
#Column(name = "NAME", nullable = false, length = 10)
private String name;
#Column(name = "DESCRIPTION", nullable = false)
private String desc;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories")
private Set<Stock> stocks = new HashSet<Stock>(0);
public Category() { }
public Category(String name, String desc) {
this.name = name;
this.desc = desc;
}
public Category(String name, String desc, Set<Stock> stocks) {
this.name = name;
this.desc = desc;
this.stocks = stocks;
}
// setters and getters
}
Stock.java
#Entity
#Table(name = "stock",uniqueConstraints = {
#UniqueConstraint(columnNames = "STOCK_NAME"),
#UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
private static final long serialVersionUID = 7788035862084120942L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "STOCK_ID", unique = true, nullable = false)
private Integer stockId;
#Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
private String stockCode;
#Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
private String stockName;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "category",
joinColumns = { #JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "CATEGORY_ID")})
private Set<Category> categories = new HashSet<Category>(0);
public Stock() { }
public Stock(String stockCode, String stockName) {
this.stockCode = stockCode;
this.stockName = stockName;
}
public Stock(String stockCode, String stockName, Set<Category> categories) {
this.stockCode = stockCode;
this.stockName = stockName;
this.categories = categories;
}
// setters and getters
}
HibernateUtil.java
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
App.java
public class App {
public static void main(String[] args) {
System.out.println("Hibernate many to many (Annotation)");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("7052");
stock.setStockName("PADINI");
Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY");
Set<Category> categories = new HashSet<Category>();
categories.add(category1);
categories.add(category2);
stock.setCategories(categories);
session.save(stock);
session.getTransaction().commit();
System.out.println("Done");
}
}
Please help me what is wrong here?
create table stock(
stock_id BIGINT(10) NOT NULL AUTO_INCREMENT,
stock_code VARCHAR(50),
stock_name VARCHAR(50),
PRIMARY KEY (`stock_id`)
);
create table Category(
stock_id BIGINT(10) NOT NULL AUTO_INCREMENT,
category_id VARCHAR(50),
name VARCHAR(50),
description VARCHAR(50),
PRIMARY KEY (`stock_id`)
)
Edit-1:
Now I am getting below error?
Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:188)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at com.mkyong.App.main(App.java:31)
Caused by: java.sql.BatchUpdateException: Table 'test.stock_category' doesn't exist
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2024)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 8 more
The name of the join table is assumed to be the table names of the
associated primary tables concatenated together (owning side first)
using an underscore.
In this case Join Table is stock_category
#JoinTable(name = "stock_category",
joinColumns = { #JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "CATEGORY_ID")})
I have an entity for storing Workshops where I am using a composite primary key.
I do not like the concept of auto-generated keys and until now have mostly used business derived keys, such as email id etc for entities. However over here, the workshop entity did not appear to have a natural candidate for primary key, so I went for a composite key.I created a WorkshopIdType which is an enum containing the three possible workshops that will be organised
public enum WorkshopIdType implements Serializable {
FOUNDATION("FND"), INTERMEIDATE("IMT"), ADVANCED("ADV");
private final String name;
private WorkshopIdType(String name) {
this.name = name;
}
#Override
public String toString() {
return this.name;
}
public boolean equals(String otherName) {
return (otherName == null) ? false : name.equals(otherName);
}
}
And then I have an Embeddable class for primary key; the combination of workshop type and date appears to me as the best fit for primary key in this scenario
#Embeddable
#Access(AccessType.FIELD)
public class WorkshopId implements Serializable {
private static final long serialVersionUID = -7287847106009163526L;
private String workshopIdType;
private Date date;
#Column(name = "id", nullable = false)
public String getWorkshopIdType() {
return workshopIdType;
}
public void setWorkshopIdType(WorkshopIdType workshopIdType) {
this.workshopIdType = workshopIdType.toString();
}
#Temporal(TemporalType.DATE)
#Column(name = "date", nullable = false)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
The entity also has a ManyToOne relationship with Venue, here again, the Venues are actually 5 of the pre-designated centres across three cities
#Entity
public class Workshop implements Serializable {
private static final long serialVersionUID = -5516160437873476233L;
private WorkshopId id;
private Venue venue;
private Integer seatsAvailable;
#EmbeddedId
public WorkshopId getId() {
return id;
}
public void setId(WorkshopId id) {
this.id = id;
}
#ManyToOne
#JoinTable(name = "workshop_venue", joinColumns = { #JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "venue_name", referencedColumnName = "name") })
public Venue getVenue() {
return venue;
}
public void setVenue(Venue venue) {
this.venue = venue;
}
#Column(name = "seats_available", nullable = false)
public Integer getSeatsAvailable() {
return seatsAvailable;
}
public void setSeatsAvailable(Integer seatsAvailable) {
this.seatsAvailable = seatsAvailable;
}
}
Problem is mapping this ManyToOne with a JoinTable in case of a composite key
#ManyToOne
#JoinTable(name = "workshop_venue", joinColumns = { #JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "venue_name", referencedColumnName = "name") })
public Venue getVenue() {
return venue;
}
This won't work as I had suspected, it cannot find a column with logical name "id". I am going with ManyToOne with JoinTable because there can be a scenario where users should get to know is there a training scheduled for the given Venue. How do I specify the referencedColumnName in this case?
Either that or I got it all wrong in the way I am modelling this?
You have a composite Primary Key represented by the embeddable WorkshopId
embedded in Workshop. Both fields of the Primary Key need to be joined to the target entity in the link table – therefore you need 2 joincolumns and one inversejoin. You just need to add the missing join;
#ManyToOne
#JoinTable(name = "workshop_venue",
joinColumns =
{ #JoinColumn(name = "workshop_id", referencedColumnName = "id"),
/* Add this joincolumn */
#JoinColumn(name = "date_id", referencedColumnName = "date") },
inverseJoinColumns =
{ #JoinColumn(name = "venue_name", referencedColumnName = "name") })
public Venue getVenue() {
return venue;
Of course you need to ensure that you link table has these three fields. I guess you are missing the date_id column.