OneToMany mapping on Embeddable key - java

I am attempting to build a permission rule for accessing items (stored in table tab) by the users (stored in table users). The availability whether to see something is stored in permissions_tabs table.
The result should be as if the statement is run (for the user with id=2):
SELECT project.tab.tab_id, project.tab.parent, project.tab.name
FROM project.tab
INNER JOIN project.permissions_tabs
ON project.tab.tab_id=project.permissions_tabs.tab_id
WHERE permissions_tabs.user_id=2 AND permissions_tabs.view=true;
I am attempting to do it via the #OneToMany annotation, but it fails - I receive the message:
Deployment failed. The message was: Exception Description: The
#JoinColumns on the annotated element [field allowedTabs] from the
entity class [class
com.jtsmr.scheduler.persistence.entities.UsersEntity] is incomplete.
When the source entity class uses a composite primary key, a
#JoinColumn must be specified for each join column using the
#JoinColumns. Both the name and the referencedColumnName elements must
be specified in each such #JoinColumn.
Before amending the DB and adding the permissions_tab, it all worked. When I added it - I was unable to write the correct #OneToMany annotation, neither I succeeded in finding manual for my case.
If it is not possible, a solution via JPQL will suffice (I was unable to construct a join operation).
Here is my setup:
DB (creation statements for easier understanding):
CREATE TABLE `users` (
`user_id` bigint(20) NOT NULL,
`username` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`name` varchar(45) NOT NULL,
`email` varchar(80) NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_id_UNIQUE` (`user_id`),
UNIQUE KEY `username_UNIQUE` (`username`)
);
CREATE TABLE `tab` (
`tab_id` bigint(20) NOT NULL AUTO_INCREMENT,
`parent` bigint(20) NOT NULL DEFAULT '0',
`name` varchar(45) NOT NULL,
PRIMARY KEY (`tab_id`)
);
CREATE TABLE `permissions_tabs` (
`user_id` bigint(20) NOT NULL,
`tab_id` bigint(20) NOT NULL,
`to_view` bit(1) DEFAULT b'0',
`to_edit` bit(1) DEFAULT b'0',
PRIMARY KEY (`user_id`,`tab_id`),
KEY `user_id_idx` (`user_id`),
KEY `tab_id_idx` (`tab_id`),
CONSTRAINT `tab_id` FOREIGN KEY (`tab_id`) REFERENCES `tab` (`tab_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
);
The JPA Mapping is as follows (functions omitted):
Tabs:
#Entity
#Table(name = "tab")
public class TabEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "tab_id", insertable = false, updatable = false)
private Long tabId;
#Column(name = "parent", insertable = false, updatable = false)
private Long parent;
#Column(name = "name", insertable = false, updatable = false)
private String name;
}
Users:
#Entity
#Table(name = "users")
public class UsersEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#OneToMany
#JoinTable(
name = "permissions_tabs",
joinColumns
= {
#JoinColumn(name = "user_id", referencedColumnName = "user_id")},
inverseJoinColumns
= {
#JoinColumn(name = "tab_id", referencedColumnName = "tab_id")})
private List<PermissionsTabsEntity> allowedTabs;
}
Primary key for the PermissionsTabsEntity class:
#Embeddable
public class PermissionsTabsPK implements Serializable {
#Column(name = "user_id")
private Long userId;
#Column(name = "tab_id")
private Long tabId;
}
And the PermissionsTabsEntity:
#Entity
#Table(name = "permissions_tabs")
public class PermissionsTabsEntity implements Serializable {
#EmbeddedId
private PermissionsTabsPK id;
#Column(name = "to_view")
private boolean toView;
#Column(name = "to_edit")
private boolean toEdit;
}
Thank you in advance!

Related

Unknown Error in ManyToOne Hibernate Mapping related to Foreign Composite Key on MySQL DB

Im Trying to map Real_States:
CREATE TABLE REAL_STATES (
address VARCHAR(30) NOT NULL,
admin_id VARCHAR(15) NOT NULL,
real_state_type_id INT(6) NOT NULL,
block VARCHAR(3) NOT NULL,
internal_id INT(5) NOT NULL,
PRIMARY KEY (address, block, internal_id),
FOREIGN KEY (real_state_type_id) REFERENCES REAL_STATE_TYPES (real_state_type_id),
FOREIGN KEY (admin_id) REFERENCES ADMINS (admin_id)
);
which is related to Resident:
CREATE TABLE RESIDENTS (
resident_id VARCHAR(15) NOT NULL,
resident_name VARCHAR(20) NOT NULL,
resident_last_name VARCHAR(20) NOT NULL,
resident_phone_number VARCHAR(15) NOT NULL,
address VARCHAR(30) NOT NULL,
block VARCHAR(3) NOT NULL,
internal_id INT(5) NOT NULL,
PRIMARY KEY (resident_id),
FOREIGN KEY (address, block, internal_id) REFERENCES REAL_STATES (address, block, internal_id)
);
Through the entity for Real_State:
#Entity
#Table(name = "real_states")
public class RealState implements Serializable{
private static final long serialVersionUID = 4033627448194380926L;
#EmbeddedId
private RealStateID realStateID;
#Column(name = "real_state_type_id")
#Enumerated(EnumType.ORDINAL)
private RealStateEnum realStateEnum;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "admin_id", insertable = true)
private Admin admin;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({#JoinColumn(name="address", referencedColumnName = "address", insertable = false, updatable = false),
#JoinColumn(name="block",referencedColumnName = "block", insertable = false, updatable = false),
#JoinColumn(name="internal_id",referencedColumnName = "internal_id", insertable = false, updatable = false)})
private Resident resident;
with the embedded entity for the composite key:
#Embeddable
public class RealStateID implements Serializable{
private static final long serialVersionUID = 6485406412363395170L;
#Column(name = "address")
private String address;
#Column(name = "block")
private String block;
#Column(name = "internal_id")
private int internal_id;
and Resident entity:
#Entity
#Table(name = "residents")
public class Resident implements Serializable {
private static final long serialVersionUID = -9052313410222202916L;
#Id
#Column(name = "resident_id")
private String resident_id;
#Column(name = "resident_name")
private String resident_name;
#Column(name = "resident_last_name")
private String resident_last_name;
#Column(name = "resident_phone_number")
private String resident_phone_number;
#Column(name = "address")
private String address;
#Column(name = "block")
private String block;
#Column(name = "internal_id")
private int internal_id;
#OneToMany(mappedBy = "resident", fetch= FetchType.EAGER)
private List<RealState> realStates;
And for this specific case, im getting the next error:
22:18:32,825 WARN [org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl] (ServerService Thread Pool -- 79) GenerationTarget encountered exception accepting command : Error executing DDL "alter table real_states add constraint FKeggvad6claf4gvemna1xdk2tm foreign key (address, block, internal_id) references residents (address, block, internal_id)" via JDBC Statement: org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table real_states add constraint FKeggvad6claf4gvemna1xdk2tm foreign key (address, block, internal_id) references residents (address, block, internal_id)" via JDBC Statement
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:559)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:504)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applyForeignKeys(AbstractSchemaMigrator.java:433)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:249)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:114)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:183)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
at org.hibernate#5.3.20.Final//org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
at org.hibernate#5.3.20.Final//org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
at org.hibernate#5.3.20.Final//org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1250)
at org.hibernate.jipijapa-hibernate5-3#23.0.1.Final//org.jboss.as.jpa.hibernate5.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
at org.jboss.as.jpa#23.0.1.Final//org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:170)
at org.jboss.as.jpa#23.0.1.Final//org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:128)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at org.wildfly.security.elytron-private#1.15.3.Final//org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:664)
at org.jboss.as.jpa#23.0.1.Final//org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:213)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.JBossThread.run(JBossThread.java:513)
Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`real_state`.`#sql-3e28_118`, CONSTRAINT `FKeggvad6claf4gvemna1xdk2tm` FOREIGN KEY (`address`, `block`, `internal_id`) REFERENCES `residents` (`address`, `block`, `internal_id`))
at com.mysql#8.0.22//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql#8.0.22//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql#8.0.22//com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql#8.0.22//com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:764)
at com.mysql#8.0.22//com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:648)
at org.jboss.ironjacamar.jdbcadapters#1.4.27.Final//org.jboss.jca.adapters.jdbc.WrappedStatement.execute(WrappedStatement.java:198)
at org.hibernate#5.3.20.Final//org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)
... 22 more
before this i was getting an error which asked me to implement "insert should be false and update should be false" that's the reason why i've added those statements to every #JoinColumn annotation, Im really new at JPA, so I'd really appreciate any kind of advice or help that can guide me to the reason behind this problem.
According to your RESIDENTS table definition:
CREATE TABLE RESIDENTS (
-- ...
FOREIGN KEY (address, block, internal_id) REFERENCES REAL_STATES (address, block, internal_id)
);
the owner side of the Resident - RealState association should be defined in the Resident entity like below:
#Entity
#Table(name = "residents")
public class Resident implements Serializable {
// ...
#ManyToOne
#JoinColumns({
#JoinColumn(name="address", referencedColumnName = "address"),
#JoinColumn(name="block", referencedColumnName = "block"),
#JoinColumn(name="internal_id", referencedColumnName = "internal_id")
})
private RealState realState;
}
and then mappedBy side in the RealState entity.
#Entity
#Table(name = "real_states")
public class RealState implements Serializable {
// ...
#OneToMany(mappedBy = "realState", fetch= FetchType.EAGER, cascade = CascadeType.ALL)
private List<Resident> resident;
}
if you are trying to save or update realstates then make sure that you are properly setting the resident object to realstate. The error log shows that there is foreign key violation while saving realstates which happens when the realstate object does not have resident object at the time of saving it.

MySQL one-to-many, Java, hibernate

First...sorry for my description...I hope I can be clear.
I want to create a project, where I have cars and drivers. One car can have one driver and one driver can have many cars.
#Entity
#Table(name = "car")
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "carid")
private int id;
#Column(name = "car_producator")
private String producator;
#Column(name = "car_model")
private String model;
#Column(name = "car_culoare")
private String culoare;
#Column(name = "car_esteInchiriata")
private boolean esteInchiriata;
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
#JoinColumn(name="driver_id")
private Driver driver;
private int car_soferID;
[...]
}
#Entity
#Table(name = "driver")
public class Driver {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "driver_id")
private int driver_id;
#Column(name = "driver_name")
private String name;
#Column(name = "driver_license")
private String license;
#Column(name = "driver_phonenr")
private String phoneNr;
#OneToMany(mappedBy = "driver", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
private List<Car> masini;
[...]
}
and this is the mysql syntax, which i don't understand very clear, if i have one to many relationships, do I need a 3rd table where i have id, carID and driverID for that car? sorry for my dummy questions
CREATE DATABASE IF NOT EXISTS `employee_directory`;
USE `employee_directory`;
DROP TABLE IF EXISTS `driver`;
CREATE TABLE `driver` (
`driver_id` int(11) NOT NULL AUTO_INCREMENT,
`driver_name` varchar(45) DEFAULT NULL,
`driver_license` varchar(45) DEFAULT NULL,
`driver_phonenr` varchar(45) DEFAULT NULL,
PRIMARY KEY (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
INSERT INTO `driver` VALUES
(1,'Tora1ie','Andrews','leslie#mail#com'),
(2,'Tora2','Baumgarten','emma#mail#com'),
(3,'Tora3i','Gupta','avani#mail#com'),
(4,'Tora4','Petrov','yuri#mail#com'),
(5,'Tora5','Vega','juan#mail#com');
create table `car` (
`carid` int unsigned not null auto_increment,
`driver_id` int unsigned not null,
`car_producator` varchar(45) DEFAULT NULL,
`car_mode` varchar(45) DEFAULT NULL,
`car_culoare` varchar(45) DEFAULT NULL,
TINYINT
`car_esteInchiriata` TINYINT(1) DEFAULT NULL,
index car_driver_index(`driver_id`),
foreign key (`driver_id`) references driver(`driver_id`) on delete cascade,
primary key(`carid`)
);
Its completely upto you to decide as both the solution will work.
For the current code it will not create a third table but every row of Car table will have a driver value.
But it would be better if you make #ManyToMany as in future it will be easy for you even if the requirement changes and will have separate table.

How to do fetch select for #ManyToMany load via spring-data?

I try load roles of the user with User entity via #ManyToMany for auth, but I get Exception.
ERROR: column user0_.role_id does not exist
I just started to learn spring data. Please help me fix this issue. Thank You.
User entity:
#Entity(name = "users")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "role_id")
private int roleId;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_id_role_id"
,
joinColumns = {
#JoinColumn(name = "user_id",
nullable = false,
updatable = false)
},
inverseJoinColumns = {
#JoinColumn(name = "role_id",
nullable = false,
updatable = false)
}
)
private List<Role> authorities;
#Column(name = "account_non_expired")
private boolean accountNonExpired;
#Column(name = "account_non_locked")
private boolean accountNonLocked;
#Column(name = "credentials_non_expired")
private boolean credentialsNonExpired;
#Column(name = "enabled")
private boolean enabled;
...
And Role entity:
#Entity(name = "user_role")
public class Role implements GrantedAuthority {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "role")
private String role;
...
My PostgreSQL schema:
CREATE TABLE IF NOT EXISTS user_role (
id SERIAL PRIMARY KEY,
role VARCHAR(10) NOT NULL
);
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL,
password VARCHAR(20) UNIQUE NOT NULL,
account_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
account_non_locked BOOLEAN NOT NULL DEFAULT TRUE,
credentials_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
enabled BOOLEAN NOT NULL DEFAULT TRUE
);
CREATE TABLE user_id_role_id (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
FOREIGN KEY (role_id) REFERENCES user_role (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
Error indicates that you don't have property role_id in table user.
You have this property in entity:
#Column(name = "role_id")
private int roleId;
but when you create table:
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL,
password VARCHAR(20) UNIQUE NOT NULL,
account_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
account_non_locked BOOLEAN NOT NULL DEFAULT TRUE,
credentials_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
enabled BOOLEAN NOT NULL DEFAULT TRUE
);
you don't have property role_id.
Just remove property roleId from User entity and it should work :)

Spring Data JPA. Using composite natural key in relationship between entities

I use Spring Data JPA (version is 1.7.2.RELEASE) and MySQL 5.5.
Here is the simplified version of my tables:
CREATE TABLE `station` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
CREATE TABLE `ticket` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`trip_id` bigint(20) unsigned NOT NULL,
`wagon_number` tinyint(4) unsigned NOT NULL,
`place_number` tinyint(4) unsigned NOT NULL,
`departure_station_id` bigint(20) unsigned NOT NULL,
`arrival_station_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `departure_trip_station_fk_idx` (`trip_id`,`departure_station_id`),
KEY `arrival_trip_station_fk_idx` (`trip_id`,`arrival_station_id`),
CONSTRAINT `arrival_trip_station_fk` FOREIGN KEY (`trip_id`, `arrival_station_id`) REFERENCES `trip_station` (`trip_id`, `station_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `departure_trip_station_fk` FOREIGN KEY (`trip_id`, `departure_station_id`) REFERENCES `trip_station` (`trip_id`, `station_id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
CREATE TABLE `train` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`number` int(11) unsigned NOT NULL,
`name` varchar(64) NOT NULL,
`enabled` bit(1) NOT NULL DEFAULT b'1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1$$
CREATE TABLE `train_station` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`train_id` bigint(20) unsigned NOT NULL,
`station_id` bigint(20) unsigned NOT NULL,
`departure_time` mediumint(8) unsigned NOT NULL,
`arrival_time` mediumint(8) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `train_station_uq` (`train_id`,`station_id`),
KEY `train_id_idx` (`train_id`),
KEY `id_idx` (`station_id`),
KEY `station_fk_idx` (`station_id`),
CONSTRAINT `station_fk` FOREIGN KEY (`station_id`) REFERENCES `station` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `train_fk` FOREIGN KEY (`train_id`) REFERENCES `train` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
CREATE TABLE `trip` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`train_id` bigint(20) unsigned NOT NULL,
`departure_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `train_id` (`train_id`),
CONSTRAINT `timetable_fk` FOREIGN KEY (`train_id`) REFERENCES `train` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=246 DEFAULT CHARSET=latin1$$
CREATE TABLE `trip_station` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`train_id` bigint(20) unsigned NOT NULL,
`station_id` bigint(20) unsigned NOT NULL,
`trip_id` bigint(20) unsigned NOT NULL,
`arrival_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`departure_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `trip_station_uq` (`trip_id`,`station_id`),
KEY `trip_fk_idx` (`trip_id`),
KEY `train_station_fk_idx` (`train_id`,`station_id`),
CONSTRAINT `train_station_fk` FOREIGN KEY (`train_id`, `station_id`) REFERENCES `train_station` (`train_id`, `station_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `trip_fk` FOREIGN KEY (`trip_id`) REFERENCES `trip` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
Here are my entities:
#Entity
#Getter
#Setter
public class Station {
#Id
private long id;
#Basic
private String name;
#OneToMany(mappedBy = "station", fetch = FetchType.LAZY)
private Collection<TrainStation> stationTrains;
}
#Entity
#Getter
#Setter
public class Ticket {
#Id
private long id;
#Basic
#Column(name = "place_number")
private byte placeNumber;
#Basic
#Column(name = "wagon_number")
private byte wagonNumber;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "trip_id", referencedColumnName = "trip_id", nullable = false),
#JoinColumn(name = "departure_station_id", referencedColumnName = "station_id", nullable = false)
})
private TripStation departureTripStation;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "trip_id", referencedColumnName = "trip_id", nullable = false),
#JoinColumn(name = "arrival_station_id", referencedColumnName = "station_id", nullable = false)
})
private TripStation arrivalTripStation;
}
#Entity
#Getter
#Setter
public class Train {
#Id
private long id;
#Basic
private int number;
#Basic
private String name;
#Basic
#Column(name = "enabled", columnDefinition = "BIT", length = 1)
private boolean enabled;
#OneToMany(mappedBy = "train", fetch = FetchType.LAZY)
private List<TrainStation> trainStations;
#OneToMany(mappedBy = "train", fetch = FetchType.LAZY)
private List<Trip> trips;
}
#Entity
#Table(name = "train_station", schema = "", catalog = "rail_db",
uniqueConstraints = #UniqueConstraint(columnNames = { "train_id", "station_id" })
)
#Getter
#Setter
public class TrainStation {
#Id
private long id;
#Basic
#Column(name = "departure_time")
private int departureTime;
#Basic
#Column(name = "arrival_time")
private int arrivalTime;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "train_id", referencedColumnName = "id", nullable = false)
private Train train;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "station_id", referencedColumnName = "id", nullable = false)
private Station station;
#OneToMany(mappedBy = "trainStation", fetch = FetchType.LAZY)
private Collection<TripStation> tripStations;
}
#Entity
#Getter
#Setter
public class Trip {
#Id
private long id;
#Basic
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
#Column(name = "departure_date")
private DateTime departureDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "train_id", referencedColumnName = "id", nullable = false)
private Train train;
#OneToMany(mappedBy = "trip", fetch = FetchType.LAZY)
private Collection<TripStation> tripStations;
}
#Entity
#Table(name = "trip_station", schema = "", catalog = "rail_db",
uniqueConstraints = #UniqueConstraint(columnNames = { "trip_id", "station_id" })
)
#Getter
#Setter
public class TripStation {
#Id
private long id;
#Basic
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
#Column(name = "arrival_date")
private DateTime arrivalDate;
#Basic
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
#Column(name = "departure_date")
private DateTime departureDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "trip_id", referencedColumnName = "id", nullable = false)
private Trip trip;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "train_id", referencedColumnName = "train_id", nullable = false),
#JoinColumn(name = "station_id", referencedColumnName = "station_id", nullable = false)
})
private TrainStation trainStation;
#OneToMany(mappedBy = "departureTripStation", fetch = FetchType.LAZY)
private Collection<Ticket> departureTickets;
#OneToMany(mappedBy = "arrivalTripStation", fetch = FetchType.LAZY)
private Collection<Ticket> arrivalTickets;
}
As you can see, my tables contain the surrogate primary keys and the composite natural keys (e.g. trip_station has UNIQUE KEY trip_station_uq (trip_id,station_id)).
For relationships between entities I offen use composite natural keys because they reflect the logic of domain.
But then I get this runtime exception:
ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/xxx/rail/config/JpaConfig.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build EntityManagerFactory
...
Caused by: org.hibernate.AnnotationException: referencedColumnNames(trip_id, station_id) of com.xxx.rail.domain.entity.Ticket.arrivalTripStation referencing com.xxx.rail.domain.entity.TripStation not mapped to a single property
...
I want to understand what is wrong?
Is it possible to use natural composite keys (which are not primary keys) for relationships when surrogate primary keys exist?

Mapping java objects using hibernate annotations?

I am attempting to map two Java classes using Hibernate. When I compile I get the following error:
Caused by: org.h2.jdbc.JdbcSQLException: Column "COMMENTS0_.DELETED" not found;
Have compared to many examples and everything seems to be correct but there is obviously an error in my mapping. Here is my code:
SQL
-- Table 'TEST_STEP_COMMENT'
CREATE TABLE IF NOT EXISTS `TEST_STEP_COMMENT` (
`id` BIGINT NULL DEFAULT NULL AUTO_INCREMENT,
`test_step_comment` TEXT NOT NULL,
`date` DATETIME NOT NULL,
`test_step_id` BIGINT NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_TEST_STEP_COMMENT_TEST_STEPS`
FOREIGN KEY (`test_step_id`)
REFERENCES `TEST_STEPS` (`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT);
CREATE INDEX `FK_TEST_STEP_COMMENT_TEST_STEPS_idx` ON `TEST_STEP_COMMENT` (`test_step_id` ASC);
CREATE TABLE IF NOT EXISTS `TEST_STEPS` (
`id` BIGINT NULL DEFAULT NULL AUTO_INCREMENT,
`deleted` BOOLEAN NULL DEFAULT FALSE,
`execute` LONGTEXT NOT NULL,
`sequence_order` INT NOT NULL,
`test_case_id` BIGINT NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_TEST_STEPS_TEST_CASES`
FOREIGN KEY (`test_case_id`)
REFERENCES `TEST_CASES` (`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT);
CREATE INDEX `FK_TEST_STEPS_TEST_CASES_idx` ON `TEST_STEPS` (`test_case_id` ASC);
JAVA
#Entity
#Audited
#Table(name = "TEST_STEPS")
public class TestStep
extends AuditedEntity
implements Identifiable<Long>, Ordered<Integer>, Comparable<TestStep> {
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "test_case_id")
private TestCase testCase;
#Column(name = "execute", nullable = false)
private String execute;
#OneToMany(mappedBy = "testStep", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#Filter(name = "deletedEntityFilter")
private Set<VerifyStep> verifications = Sets.newLinkedHashSet();
#Column(name = "sequence_order", nullable = false)
private Integer sequenceOrder = 0;
#OneToMany(mappedBy = "testStep", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<TestStepComment> comments = Sets.newLinkedHashSet();
#Column(name = "result")
private Integer result;
#Column(name = "data")
private String data;
//getters/setters etc
}
#Entity
#Audited
#Table(name = "TEST_STEP_COMMENT")
public class TestStepComment
extends AuditedEntity
implements Identifiable<Long>{
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "test_step_id")
private TestStep testStep;
#Column(name = "test_step_comment")
private String comment;
#Column(name = "date")
private Date date;
#Override
public Long getId() {
return id;
//getters/setters etc
}
If anyone has any suggestions of what may be causing my problem it would be much appreciated because my mapping seems to be correct based on multiple examples that I have looked at. Thanks!

Categories

Resources