can sameone help me with problem with saving object to PostgreSQL databse? I use serial id and annotation #SequenceGenerator cannot get me some id from sequence, witch have been created automaticaly. (serial) The sequence is "user_id_user_sec".
I can save one entity, but second throw exception:
ERROR: ERROR: duplicate key value violates unique constraint "user_pkey"
Detail: Key (id_user)=(0) already exists.
Info: HHH000010: On release of batch it still contained JDBC statements
Severe: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelega te.java:129)
My entity, witch I can save to database:
#Entity
#Table(name = "\"User\"")
public class User implements java.io.Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="seq")
#SequenceGenerator(name="seq", sequenceName="user_id_user_seq", allocationSize=1)
private int idUser;
#Column
private String apiKey;
#Column
private String email;
#Column
private String name;
#Column
private String password;
#Column
private boolean isAdmin;
#Column
private boolean enabled;
private Set deviceWatchedByUsers = new HashSet(0);
and getters and setters and my UserDAO's method, witch save this entity is:
public static Integer addUser(User u){
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
Integer userId = null;
try{
tx = session.beginTransaction();
User user = u;
userId = (Integer) session.save(user);
tx.commit();
}catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally {
session.close();
}
return userId;
}
And script to create database is:
CREATE TABLE "user"
(
id_user serial NOT NULL,
api_key character varying(255),
email character varying(255) NOT NULL,
name character varying(255) NOT NULL,
password character varying(255) NOT NULL,
is_admin boolean NOT NULL,
enabled boolean NOT NULL,
CONSTRAINT user_pkey PRIMARY KEY (id_user),
CONSTRAINT user_email_key UNIQUE (email)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "user"
OWNER TO postgres;
You need to change the DB table id_user to:
id_user bigint NOT NULL
You don't need the serial type, since it's Hibernate assigning the id column using a sequence call.
If you wanted to have the database in charge of assigning ids, then the SEQUENCE generator would simply compete against the database id generation strategy.
In that case you would need a "select" generator instead.
Related
In my rest API, I have Role and RolePrivilege entities with #Entity annotation. There are some columns in each entity. I need to set a one-to-many relationship with these two. One role has many role privileges and one role privilege can only have one role. In my DB script file, I set it as
-- -----------------------------------------------------
-- Table `wdc`.`role`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `wdc`.`role` (
`roleId` INT NOT NULL AUTO_INCREMENT ,
`roleName` VARCHAR(45) NOT NULL ,
`disabled` INT(1) ZEROFILL NULL ,
PRIMARY KEY (`roleId`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `wdc`.`rolePrivileges`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `wdc`.`rolePrivileges` (
`privilegeId` INT NOT NULL AUTO_INCREMENT ,
`privilegeDescription` VARCHAR(45) NOT NULL ,
`roleId` INT NULL ,
`disabled` INT(1) ZEROFILL NULL ,
`lastModifiedUser` VARCHAR(30) NULL DEFAULT NULL,
`lastModifiedDateTime` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`privilegeId`),
FOREIGN KEY (`roleId`)
REFERENCES `wdc`.`role` (`roleId`)
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
This creates database fine. I created Role entity as follows,
#Entity
#Table(name = "role", schema = "wdc", catalog = "")
public class Role implements Serializable {
#Id
#Column(name = "roleid", nullable = false, unique = true)
#GeneratedValue(strategy=GenerationType.IDENTITY)
#OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
private Set<RolePrivilege> rolePrivileges;
public Role(int roleId, String roleName, Integer disabled, RolePrivilege rolePrivileges) {
this.roleId = roleId;
this.roleName = roleName;
this.disabled = disabled;
this.rolePrivileges = Stream.of(rolePrivileges).collect(Collectors.toSet());
this.rolePrivileges.forEach(x -> x.setRoleId(this));
}
}
RolePrivilege entity as follows,
#Entity
#Table(name = "roleprivileges", schema = "wdc", catalog = "")
public class RolePrivilege implements Serializable {
#Id
#Column(name = "privilegeid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
#ManyToOne
#JoinColumn
private Role role;
public RolePrivilege(int privilegeId, String privilegeDescription, Integer disabled, String lastModifiedUser, Timestamp lastModifiedDateTime) {
this.privilegeId = privilegeId;
this.privilegeDescription = privilegeDescription;
this.disabled = disabled;
this.lastModifiedUser = lastModifiedUser;
this.lastModifiedDateTime = lastModifiedDateTime;
}
}
I used CrudRepository interface to save new entries to database.
#Repository
public interface RoleRepository extends CrudRepository<Role, Integer> {
}
#Repository
public interface RolePrivilegeRepository extends CrudRepository<RolePrivilege, Integer> {
}
This is my service file for add new role privilege,
// ---------------------------------
// add new role privilege
// ---------------------------------
public String addRolePrivilege(RolePrivilege rolePrivilege){
try {
rolePrivilegesRepository.save(rolePrivilege);
return "Saved";
} catch (Exception e){
return "Failed";
}
}
As last I used Controller file as this,
// ---------------------------------
// add new role privilege to database
// ---------------------------------
#PostMapping(path = "/")
public #ResponseBody String addRolePrivilege(#RequestBody RolePrivilege rolePrivilege){
return rolePrivilegesService.addRolePrivilege(rolePrivilege);
}
But still when I trying to save new role privilege it saves with out roleId in rolePrivilege table.
I tried it this way,
{
"privilegeDescription": "add user",
"role": [
{
"roleId": "1",
"roleName": "user1",
"disabled": 0
}
],
"disabled": 0,
"lastModifiedUser": "1",
"lastModifiedDateTime": "2020-03-11T17:58:14.361+0000"
}
Where do I need to change? Please help me.
When I send request to save new role privilege it returns saved but when I check it with mysql workbench, the roleId column in emplty.
You have a raw #JoinColumn in RolePrivilege, change it, so that the name of the column is configured: #JoinColumn(name = "roleId").
Also you're saving RolePrivilege, but the changes are not cascading, change the mapping to:
#ManyToOne(cascade = CascadeType.ALL)
P.S.: Prefer Lists over Sets in -to-many mapping for performance reasons.
Firstly, do not return String(wrap it to class for example to RolePriviligueResponse with String status as response body), secondly you dont need #ResponseBody annotation, your #PostMapping annotation already has it, third - dont use Integer for ID, better use Long type.
And you did not provide the name of #JoinColumn(name="roleId")
I am working on a school project, and I am having trouble with joining tables so I can display output in JSP file using JSTL. I will provide all necessary code. I know that I need to connect entities somehow, but I don't know how.
SQL:
CREATE TABLE IF NOT EXISTS `totelegram`.`contacts` (
`id` INT NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL,
`last_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL,
`phone_number` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC),
UNIQUE INDEX `phone_number_UNIQUE` (`phone_number` ASC))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `totelegram`.`messages` (
`id_message` INT NOT NULL AUTO_INCREMENT,
`message` VARCHAR(2000) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT
NULL,
`time` VARCHAR(45) NOT NULL,
`contacts_id` INT NOT NULL,
PRIMARY KEY (`id_message`),
UNIQUE INDEX `id_message_UNIQUE` (`id_message` ASC),
INDEX `fk_messages_contacts_idx` (`contacts_id` ASC),
CONSTRAINT `fk_messages_contacts`
FOREIGN KEY (`contacts_id`)
REFERENCES `totelegram`.`contacts` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Contacts.java
#Entity(name = "contacts")
public class Contacts implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#javax.persistence.Column(name = "first_name")
private String firstName;
#javax.persistence.Column(name = "last_name")
private String lastName;
#javax.persistence.Column(name = "phone_number")
private String phoneNumber;
...getters/setters, constructor, toString...
Messages.java
#Entity(name = "messages")
public class Messages implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#javax.persistence.Column(name = "id_message")
private int id;
private String message;
private String time;
#javax.persistence.Column(name = "contacts_id")
private int contactsId;
...getters/setters, constructor, toString...
MessagesRepository.java
public interface MessagesRepository extends JpaRepository<Messages, Integer> {
//custom query which will output this
//SELECT b.message, b.time, b.contacts_id, a.first_name, a.last_name FROM messages AS b INNER JOIN contacts as A ON (b.contacts_id=a.id) ORDER BY time ASC;
public List<Messages> findAll();
}
I hope I was clear. Thanks to everybody in advance.
As far as i understand, one contact can have N messages and you cannot have a Message without the Contact, right?
Since you have relations between classes, you have to use specific annotations in jpa, for example:
in the Message Class, you should use the #ManyToOne annotation, since you have Many Messages for One Contact. The JoinColumn will input the contacts_id in the Messages Table.
#ManyToOne
#JoinColumn(name = "contacts_id")
private Contacts contact;
in the Contacts Class, you should use #OneToMany annotation, since One Contact has Many Messages. The mappedBy makes a reference in contact at the Message Class.
#OneToMany(mappedBy = "contact")
private List<Messages> messages = new ArrayList<>();
So far you made a Bidirectional reference between Contacts and Messages. Now in your service class, i would recommend you find the Messages through the Contacts, since you cannot have a message without the contact. Its a Repository principle.
Contacts con = repository.findOne(1);
con.getMessages();
btw, sorry for the bad english.
I'd like to use unidirectional relationship for my JPA instances (Hibernate 4.3.10)
RegionalCountry -> RegionalArea1 -> RegionalArea2
#Entity
public class RegionalCountry {
#Id
#Column(unique = true, nullable = false, updatable = false, length = 36)
private String uuid = UUID.randomUUID().toString();
private String countryName;
private String countryCode;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
private List<RegionalArea1> regionalArea1;
...//getters&setters
}
#Entity
public class RegionalArea1 {
#Id
#Column(unique = true, nullable = false, updatable = false, length = 36)
private String uuid = UUID.randomUUID().toString();
private String area1Name;
private String area1Code;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
private List<RegionalArea2> regionalArea2;
...//getters&setters
}
#Entity
public class RegionalArea2 {
#Id
#Column(unique = true, nullable = false, updatable = false, length = 36)
private String uuid = UUID.randomUUID().toString();
private String area2Name;
private String area2Code;
...//getters&setters
}
Then I want to use Spring JpaRepository to fetch the country and its regional area instances by country code:
public interface RegionalCountryRepository extends JpaRepository<RegionalCountry, UUID> {
public RegionalCountry findOneByCountryCode(String countryCode);
}
When I call
regionalCountryRepository.findOneByCountryCode(countryCode);
SQLException occurs: Unknown column 'regionalar0_.regional_country' in 'field list'
the same exception is for regionalCountryRepository.findAll();
Is there a way to use unidirectional relationship between regional instances and do not get this error?
Surprisingly, unit tests with embedded db work well for the code above, but when we deal with the real MySQL database the exception occurs.
#Test
public void testFindByCountryCode() {
southernArea = new RegionalArea1();
southernArea.setArea1Code("00");
southernArea.setArea1Name("SOUTHERN");
chejuDoArea = new RegionalArea1();
chejuDoArea.setArea1Code("00");
chejuDoArea.setArea1Name("CHEJU-DO");
korea = new RegionalCountry();
korea.setCountryName("Korea, Republic of");
korea.setCountryCode("KOR");
korea.setRegionalArea1s(Arrays.asList(southernArea, chejuDoArea));
repository.save(korea);
RegionalCountry countryFetched = repository.findOneByCountryCode("KOR");
Assert.assertNotNull(countryFetched);
}
Update: the schema is the following
CREATE TABLE REGIONAL_AREA2(
UUID VARCHAR(36) NOT NULL,
AREA2CODE VARCHAR(255),
AREA2NAME VARCHAR(255)
);
CREATE TABLE REGIONAL_AREA1(
UUID VARCHAR(36) NOT NULL,
AREA1CODE VARCHAR(255),
AREA1NAME VARCHAR(255)
);
CREATE TABLE REGIONAL_AREA1_REGIONAL_AREA2(
REGIONAL_AREA1_UUID VARCHAR(36) NOT NULL,
REGIONAL_AREA2_UUID VARCHAR(36) NOT NULL
);
CREATE TABLE REGIONAL_COUNTRY(
UUID VARCHAR(36) NOT NULL,
COUNTRY_CODE VARCHAR(255),
COUNTRY_NAME VARCHAR(255)
);
CREATE TABLE REGIONAL_COUNTRY_REGIONAL_AREA1(
REGIONAL_COUNTRY_UUID VARCHAR(36) NOT NULL,
REGIONAL_AREA1_UUID VARCHAR(36) NOT NULL
);
There may be several reasons:
I do not see any mapping from your class variables to table field regional_country. Please make sure to use annotation #Column to specify the correct table field which the variable maps to. For instance, if variable countryCode maps to table field country_code, you should annotate like this: #Column(name = "country_code") private int countryCode;
For variables private String countryName; private String countryCode; if they have a mapping field in your db schema, please use #Column to annotate them
It would be helpful if you provide more information about your question: e.g., your db schema.
I try to reproduce your problem using just Hibernate Session without any JpaRepository. I have to change mapping for all collection associations from List to Set cause of the "cannot simultaneously fetch multiple bags" error
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<RegionalArea1> regionalArea1;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<RegionalArea2> regionalArea2;
Everything works fine without any errors. May be, It will help you too. If It will no help:
Hibernate thinks that the REGIONAL_COUNTRY_REGIONAL_AREA1 join table has the regional_country column, but this table has the REGIONAL_COUNTRY_UUID. So try to specify join column names by #JoinTable annotation, or recreate database schema, or change the naming strategy, if you specify it.
SQL generated by Hibernate for search country by country code
select
this_.f_uuid as f_uuid1_3_2_,
this_.f_country_code as f_countr2_3_2_,
this_.f_country_name as f_countr3_3_2_,
regionalar2_.fk_regional_country as fk_regio1_4_4_,
regionalar3_.f_uuid as fk_regio2_4_4_,
regionalar3_.f_uuid as f_uuid1_0_0_,
regionalar3_.f_area1code as f_area2_0_0_,
regionalar3_.f_area1name as f_area3_0_0_,
regionalar4_.fk_regional_area1 as fk_regio1_1_5_,
regionalar5_.f_uuid as fk_regio2_1_5_,
regionalar5_.f_uuid as f_uuid1_2_1_,
regionalar5_.f_area2code as f_area2_2_1_,
regionalar5_.f_area2name as f_area3_2_1_
from
spring_regional_countries this_
left outer join
spring_regional_countries_regional_area1s regionalar2_
on this_.f_uuid=regionalar2_.fk_regional_country
left outer join
spring_regional_area1s regionalar3_
on regionalar2_.fk_regional_area1=regionalar3_.f_uuid
left outer join
spring_regional_area1s_regional_area2s regionalar4_
on regionalar3_.f_uuid=regionalar4_.fk_regional_area1
left outer join
spring_regional_area2s regionalar5_
on regionalar4_.fk_regional_area2=regionalar5_.f_uuid
where
this_.f_country_code=?
Thanks for all answers but the problem was in REGIONAL_COUNTRY_REGIONAL_AREA1 table column names. Postfix _UUID at the end of the column name confuses MySQL.
It's possible to fix this problem renaming columns of intermediate datatables
DROP TABLE IF EXISTS REGIONAL_AREA1_REGIONAL_AREA2;
DROP TABLE IF EXISTS REGIONAL_AREA1_REGIONAL_AREA2;
CREATE TABLE REGIONAL_AREA1_REGIONAL_AREA2(
REGIONAL_AREA1 VARCHAR(36) NOT NULL,
REGIONAL_AREA2 VARCHAR(36) NOT NULL
);
CREATE TABLE REGIONAL_COUNTRY_REGIONAL_AREA1(
REGIONAL_COUNTRY VARCHAR(36) NOT NULL,
REGIONAL_AREA1 VARCHAR(36) NOT NULL
);
I use Hibernate to control my database and I have 2 tables:
CREATE TABLE IF NOT EXISTS `User`(
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL DEFAULT '',
`account` VARCHAR(255) NOT NULL DEFAULT '',
`password` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
)
CREATE TABLE IF NOT EXISTS `Project` (
`id` INT NOT NULL AUTO_INCREMENT,
`manager` INT NOT NULL,
`name` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
FOREIGN KEY (`manager`) REFERENCES `User`(`id`)
)
And I have done the mapping:
User:
// ... import code
#Entity
#Table
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String name, account, password;
#OneToMany(mappedBy = "manager")
private List<Project> projects;
public User() {
}
// ... Getter & Setter code
}
Project:
// ... import code
#Entity
#Table
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String name;
#ManyToOne
#JoinColumn(name = "manager")
private User manager;
public Project () {
}
// ... Getter & Setter code
}
I want to know whether it is possible when I select projects, the project will include its manager data but not have password.
In other ways, I want that each project I get will like this (format as JSON):
{
"id": 0,
"name": "A test project",
"manager": {
"id": 0,
"name": "John Smith"
"accound": "user1",
"password": null
}
}
1. Projection
A projection could be used to limit the fields you want to bring into memory, you could get a projection of all fields except the password.
2. Lazy
Another option can be adding the lazy annotation to the field:
#Basic(fetch = FetchType.LAZY)
#Column(...)
private String password;
3. HQL query
Another way would be to use a direct HQL query and load only the required fields, from this answer.
If you don't want to map this field at all, you could use #Transient annotation:
#Transient
private String password;
If you simply don't want to show this field when you convert the object to a particular JSON representation, then this is a data representation problem, not a ORM mapping problem. You should skip this field when you convert your object to JSON. The implementation depends on what JSON converter you are using. For instance, if you use Jackson, then the #JsonIgnore annotation is what you need.
I am using: Spring 4, Hibernate 4, SQL Server 2008
I know how to do it with SQL Server 2008 from this question response How do I create a unique constraint that also allows nulls?
But since I don't generate any manual SQL code during the creation of the table, is it possible to generate a "where clause" in my constraint through Hibernate annotations in my Entity class?
My DDL is created from scratch with the java entity definition as follows:
#Entity
#Table(name="Neighborhood",
uniqueConstraints = {#UniqueConstraint(columnNames = {"codecnbv","zipcode"})})
#JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
public class Neighborhood implements Serializable {
private String id;
private String codecnbv;
private String zipcode;
#Id
#Column(name="id", nullable=false, unique=true, length=2)
public String getId() {
return this.id;
}
#Column(name="codecnbv", nullable=true, length=12) //explicitly nullable
public String getCodecnbv() {
return codecnbv;
}
#Column(name="zipcode", nullable=true, length=5) //explicitly nullable
public String getZipcode() {
return zipcode;
}
}
However, as soon as I add data and try to enter a second record with NULL in column codecnbv and/or zipcode, I receive an exception that says I've violated the unique constraint.
The requirement I have says that I must allow multiple null values, and when the value is not null, then I should have unique values i.e.
For zipcode column
56000 --ok
NULL --ok
34089 --ok
NULL --ok
34089 --Not allowed
34567 --ok
It is not an issue of Hibernate but of SQL Server, which considers NULL a value and does not allow a second NULL value. Wicked, I know.
Some links:
How do I create a unique constraint that also allows nulls?
http://sqlmag.com/database-development/multiple-nulls-unique-constraints