In hibernate I have created a one-to-many relationship between user and roles.
More then one user can be associated with a role, but a user can be associated with just one role.
In User class, I have
#ManyToOne
#JoinColumn(name = "role_id")
private Role role_id;
In Role Class, I have
#OneToMany(mappedBy="role_id", fetch=FetchType.LAZY)
private Collection<User> userList = new ArrayList<User>();
If I am saving a new user as :
{
"userName" : "Michael",
"role_id" : {
"id" : 8
}
}
It saves user even when role table has no role with id as 8( and no entry is done in role table).
I want that I should get a referential integrity error whenever I am saving a user with a non existent role.
What should I change?
My Users table is created as:
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`email` varchar(255) DEFAULT NULL,
`mobile` varchar(255) DEFAULT NULL,
`username` varchar(255) NOT NULL,
`role_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_abcdef` (`role_id`),
CONSTRAINT `FK_abcdef` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Do you have FK constraint in your tables in the database? Maybe this if you use mySql can help you. Or alternatively you can set the restriction in your database by your own.
In your #OneToMany annotation you probably need to add targetEntity = User.class. That is because of the following reasons:
java generics use type erasure, which means that in the generated bytecode, your userList is of type Collection, not of type Collection<User>. So, hibernate has no clue what the target entity is, unless you explicitly tell it.
Hibernate generally likes to follow a silent error / hidden error approach, which means that it silently ignores problems the moment they happen (as for example the moment where it has no clue what type your collection elements are) and to fail later, when the cause of the problem is not very clear anymore. (As for example when you execute a query which should fail, and it doesn't, or you execute a query which should fetch something, and it fetches nothing.)
As of java 9, the compiler does actually store information about the actual type arguments used when creating generic fields within the generated .class files, and it is possible to discover that information using reflection, but I am not aware of hibernate having been updated to check this information.
Related
I have followin sql:
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`power_id` int(11) NOT NULL
)
ALTER TABLE `user`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `power_id` (`power_id`),
ALTER TABLE `user`
ADD CONSTRAINT `FK_user_power` FOREIGN KEY (`power_id`) REFERENCES `power` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
CREATE TABLE `power` (
`id` int(11) NOT NULL,
`updated_date` date NOT NULL
)
( its hand typed )
However when i do view Persistence -> Generate Persistance Mapping -> By Database Schema It generated this in User entity class:
private PowerEntity powerByPowerId;
#ManyToOne
#JoinColumn(name = "power_id", referencedColumnName = "id", nullable = false)
public PowerEntity getPowerByPowerId() {
return powerByPowerId;
}
which is clearly 1:n relation ( e.g multiple users have one power ) while sql says about 1:1 relation.
NOw i am unsure if my sql is wrong or intelij generated wrong relatios.
How to deal with it? My database schema is not small and so far i have noticed only this mistake, however i am not sure if its my fault or intelij's mapping is producing wrong entity tables ( which would mean i could find another badly generated entity ).
Thanks for help.
I have a table created on mysql with following sql
CREATE TABLE `ssk_cms_category_transaction_type_relation` (
`categoryId` int(11) NOT NULL,
`typeId` int(11) NOT NULL,
`createdTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`categoryId`,`typeId`),
KEY `FK_ssk_cms_category_transaction_type_relation1` (`typeId`),
CONSTRAINT `FK_ssk_cms_category_transaction_type_relation` FOREIGN KEY (`categoryId`) REFERENCES `ssk_cms_content_category` (`contentCategoryId`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK_ssk_cms_category_transaction_type_relation1` FOREIGN KEY (`typeId`) REFERENCES `ssk_transaction_type` (`typeId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
While trying to generate its model using hibernate persistence tool in intellij, if I check on show default relationships I get the following error, can anyone help me out in understanding this. I tried googling but no solution found
The message tells that mentioned relations of the ssk_cms_category_transa... table reference another table which is not included into the model generation. So you should select this another table including it into generation to avoid the error.
Let's say I have an object
class User
{
int id;
String name;
String password;
List<Property> properties;
}
And
class Property
{
int id;
String key;
String value;
}
The table in MySQL however is slightly different.
CREATE TABLE `user` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45),
`password` VARCHAR(45),
PRIMARY KEY (`id`));
And
CREATE TABLE `property` (
`id` INT NOT NULL AUTO_INCREMENT,
`key` VARCHAR(45) NULL,
`value` VARCHAR(45) NULL,
`userId` INT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `userId`
FOREIGN KEY (`userId`)
REFERENCES `user` (`userId`));
How would I create hibernate annotations so that if I would like to save user object I will end up saving/creating new properties accordingly?
I really do not want to put User object inside Property object for this to happen.
You can achieve this using unidirectional OneToMany mapping, but it will create an extra table with userId and propertyId column and your property table will not need userId column. In this case you will be able to get all properties of user, but you won't be able to query a particular property belongs to which user.
If you want to have user information in a property object, you must use bi-directional OneToMany mapping and for that you will need put user inside Property class.You can control the initialization of User object inside Property class while fetching data from database by configuring fetch type for User. By default, fetch type is LAZY, meaning User object will fetched from database only when you use it.
In my project, an Admin (User) can set to receive scheduled emails about any User he chooses.
I need to have a database of the following design:
TABLE User (
UserId INT PRIMARY KEY AUTO_INCREMENT,
Email VARCHAR,
FirstName VARCHAR,
LastName VARCHAR
IsAdmin BOOL,
...
)
TABLE Email_Schedule (
ScheduleId INT PRIMARY KEY AUTO_INCREMENT, /* this is not necessary */
AdminId INT, /* could be replaced by a composite foreign primary keys */
UserId INT,
FOREIGN KEY (AdminId) REFERENCES User (UserId),
FOREIGN KEY (UserId) REFERENCES User (UserId)
)
The following code in my Java classes for JPA entity:
#Entity
public class Email_Schedule {
#Id
private int scheduleId;
#ManyToOne(targetEntity = User.class)
private List<User> admins = new LinkedList<>();
#ManyToOne(targetEntity = User.class)
private List<User> users = new LinkedList<>();
public Email_Schedule() {
super();
}
public Email_Schedule(User admin, User user) {
super();
this.admins.add(admin);
this.users.add(user);
}
// setters and getters...
generates a database of the following schema:
TABLE USER (
...
)
TABLE SCHEDULE (
ScheduleId INT PRIMARY KEY AUTO_INCREMENT
)
TABLE Email_Schedule (
ScheduleId INT,
Users INT,
Admins INT,
FOREIGN KEY (ScheduleId) REFERENCES SCHEDULE(ScheduleId),
FOREIGN KEY (Users) REFERENCES USER (UserId),
FOREIGN KEY (Admins) REFERENCES USER (UserId)
)
My question is why did it create a useless table for ScheduleId and referenced it from another table instead of just using it directly in Email_Schedule table?
The problem seems to be with the ScheduleId.. I tried not to use it by creating IdClass but I got different errors and wrong database designs.
EclipseLink is using TABLE for generating sequence for scheduleId.
This seems to be the default.
You can use a table for identifier generation on any database. This
strategy is completely portable across databases and will be
automatically generated for you when schema generation is enabled.
As per EclipseLink Documentation, you may have to use generation strategy of IDENTITY for scheduleId to avoid the TABLE appraoch.
#GeneratedValue(strategy=GenerationType.IDENTITY)
Note that if you use AUTO strategy as shown below, then, even in that case, EclipseLink may pick TABLE strategy for ID generation.
#GeneratedValue(strategy=GenerationType.AUTO)
Using a Default Generation Strategy
Specifying a strategy of AUTO
allows EclipseLink to select the strategy to use. Typically,
EclipseLink picks TABLE as the strategy, since it is the most portable
strategy. However, when AUTO is specified, schema generation must be
used at least once in order for the default table to be created in the
database.
More details here at PrimaryKey and GeneratedValue Documentation
I have two object. Let it be company and employee.
CREATE TABLE company (
company_id BIGINT(20) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
chief_id BIGINT(20) NOT NULL,
PRIMARY KEY (company_id),
CONSTRAINT fk_company_chief
FOREIGN KEY (chief_id)
REFERENCES employee (employee_id)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
CREATE TABLE employee(
employee_id BIGINT(20) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
company_id BIGINT(20) NOT NULL,
PRIMARY KEY (employee_id),
CONSTRAINT fk_employee_company
FOREIGN KEY (chief_id)
REFERENCES employee (company_id)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
And my classes look like:
class Employee {
long id;
String name;
Company company;
}
class Company{
long id;
String name;
Employee chief;
}
Then I want to delete company with all its employees. I do it in a single transaction. I am getting smth like "java.sql.BatchUpdateException: Column 'chief_id' cannot be null"
I am able to delete only after making one of the columns nullable. For example "chief_id BIGINT(20) NULL," and then making company.chief=null before delete.
In the project we don't use Hibernate cascades and I am not able to change Database cascades.
We are using MySql 5.0.
I need smth like: disable constraints->remove entity->enable constraints. The disabled state should be accessible only within current transaction. I thought it was default behavior.
If your DBMS supports it, you can declare one of your constraints as deferrable initially deferred, so that it would be checked at the end of transaction.
You should use Hibernate cascades. Disabling/enabling database constraints is a DDL operation and it is committed immediately, there is no way to hide the "disabled state" from other transactional contexts.
If you cannot use Hibernate cascades, what you could do is use a dummy company (company_id=-1 for instance) and a dummy chief Employee object (employee_id=-1). DummyChief belongs to the company DummyCompany, and DummyCompany's chief is DummyChief.
You could then proceed in the following order:
1/ Delete all non-chief Employees in the Company.
2/ Set the Company chief employee to DummyChief (employee_id=-1)
3/ Delete the Chief employee.
4/ Delete the Company company.