I'am trying to do an unidirectional #OneTaMany relationship like in the Hibernate User Guide (2.7.2) but when I try to save the following object in a MariaDB Database:
Filter filter = new Filter("TLS_A320");
filter.addConstraint(new Constraint(ConstraintType.DEPARTURE, "TLS"));
filter.addConstraint(new Constraint(ConstraintType.AIRCRAFT, "A320"));
session.save(filter);
I got this exception :
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Filter_idFilter' in 'field list'
Here are the 2 classes:
Filter.java
public class Filter {
#Id
#Column(name = "idFilter")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<Constraint> constraintList;
//more code
};
Constraint.java
public class Constraint {
#Id
#Column(name = "idConstraint")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "type")
#Enumerated(EnumType.ORDINAL)
private ConstraintType constraintType;
#Column(name = "value")
private String value;
//more code
}
And here is the tables definition :
CREATE TABLE `Constraint` (
idConstraint INT NOT NULL AUTO_INCREMENT,
type INT NOT NULL,
value VARCHAR(10) NOT NULL,
PRIMARY KEY (idConstraint)
);
CREATE TABLE Filter (
idFilter INT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
PRIMARY KEY (idFilter)
);
CREATE TABLE Filter_Constraint (
idFilter INT UNIQUE NOT NULL,
idConstraint INT NOT NULL,
CONSTRAINT fk_Filter_Constraint_Filter FOREIGN KEY (idFilter) REFERENCES Filter(idFilter),
CONSTRAINT fk_Filter_Constraint_Constraint FOREIGN KEY (idConstraint) REFERENCES `Constraint`(idConstraint)
);
It seems to me that that Filter and Constraint insertions are fine and the exception happens when inserting in the Filter_Constraint table :
DEBUG org.hibernate.SQL - insert into Filter (name) values (?)
DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 4
DEBUG org.hibernate.SQL - insert into `Constraint` (type, value) values (?, ?)
DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 5
DEBUG org.hibernate.SQL - insert into `Constraint` (type, value) values (?, ?)
DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 6
DEBUG org.hibernate.SQL - insert into `Filter_Constraint` (Filter_idFilter, `constraintList_idConstraint`) values (?, ?)
DEBUG org.hibernate.engine.jdbc.spi.SqlExceptionHelper - could not execute statement [n/a]
DEBUG com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Filter_idFilter' in 'field list'
I'am pretty new to Hibernate and I just can't figure out what I did wrong.
You didn't define any join column or inverse join column on constraintList, hence Hibernate will autogenerate column names which most probably results in the name Filter_idFilter.
The entity name will be part of the name since Constraints could have an id field with the same name, i.e. idFilter. Of course you know that isn't the case but Hibernate doesn't (or at least the column name generation code isn't that complex) and hence it has to assume that could be the case.
The same is true for join table names so you'll probably want to use #JoinTable along with the definition of join columns and inverse join columns on constraintList. However, since the relation is OneToMany anyways, why don't you add a back reference to Constraint, add the filter's id to table Constraint and get rid of the join table entirely?
Related
I have simple Spring Boot app with in-memory H2 database, and I have two entities:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class DictEntity{
#Id
Long id;
#Column(unique = true)
String name;
}
and
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class ComplexEntity {
#Id
Long id;
#Column
String name;
#Column
#OneToMany(cascade = CascadeType.ALL)
List<DictEntity> properties;
}
Hibernate generates me such DDL:
Hibernate: create table complex_entity (id bigint not null, name varchar(255), primary key (id))
Hibernate: create table complex_entity_entities (complex_entity_id bigint not null, entities_id bigint not null)
Hibernate: create table dict_entity (id bigint not null, name varchar(255), primary key (id))
Hibernate: alter table complex_entity_entities add constraint UK_nxr507qlfqwm2vk6gqes2b3lc unique (entities_id)
Hibernate: alter table dict_entity add constraint UK_m9sbjtymc6urpykp5ko3faep1 unique (name)
Hibernate: alter table complex_entity_entities add constraint FKn66943skv39n53nfkj6wwsnl2 foreign key (entities_id) references dict_entity
Hibernate: alter table complex_entity_entities add constraint FK6wqn8as4rkbi5caulfyex6sxm foreign key (complex_entity_id) references complex_entity
And then I have a code:
foo = anEntityRepository.save(new DictEntity(1L, "foo"));
bar = anEntityRepository.save(new DictEntity(2L, "bar"));
ComplexEntity m1 = complexEntityRepository.save(new ComplexEntity(1l, "m1", Collections.singletonList(foo)));
ComplexEntity m2 = complexEntityRepository.save(new ComplexEntity(2l, "m2", Collections.singletonList(foo)));
On last line i got an Exception:
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PUBLIC.UK_NXR507QLFQWM2VK6GQES2B3LC_INDEX_9 ON PUBLIC.COMPLEX_ENTITY_ENTITIES(ENTITIES_ID) VALUES 1"; SQL statement:
insert into complex_entity_entities (complex_entity_id, entities_id) values (?, ?)
What went wrong?
Your error
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PUBLIC.UK_NXR507QLFQWM2VK6GQES2B3LC_INDEX_9 ON PUBLIC.COMPLEX_ENTITY_ENTITIES(ENTITIES_ID) VALUES 1"; SQL statement:
insert into complex_entity_entities (complex_entity_id, entities_id) values (?, ?)
has nothing to do with what you suspect in the question as a cause, as you mention the
#Column
#OneToMany(cascade = CascadeType.ALL)
List<DictEntity> properties;
Probably the
#NoArgsConstructor
public class ComplexEntity {
...
has also another field which is used to create the mapping table complex_entity_entities and this is the one that is failing.
Update the question with all relevant code to find exactly the issue. I expect that you have a field named entities upon ComplexEntity.class.
I suspect though that the ComplexEntity has reference upon other ComplexEntity and this is the type of issue here.
I want to persist a objects by using JPA in a MYSQL-database. Here ist my create script:
CREATE TABLE toolboxAccount (
idtoolboxAccount INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(30) NOT NULL ,
password_2 VARCHAR(30) NOT NULL ,
PRIMARY KEY(idtoolboxAccount));
CREATE TABLE config (
idconfig INT NOT NULL AUTO_INCREMENT,
toolboxAccount_idtoolboxAccount INTEGER UNSIGNED NOT NULL ,
defaultExportPath VARCHAR(255) NULL ,
PRIMARY KEY(idconfig) ,
INDEX config_FKIndex1(toolboxAccount_idtoolboxAccount),
FOREIGN KEY(toolboxAccount_idtoolboxAccount)
REFERENCES toolboxAccount(idtoolboxAccount)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE connection (
idconnection INT NOT NULL AUTO_INCREMENT,
toolboxAccount_idtoolboxAccount INTEGER UNSIGNED NOT NULL ,
url VARCHAR(255) NULL ,
username VARCHAR(30) NULL ,
password_2 VARCHAR(30) NULL ,
site VARCHAR(30) NULL ,
PRIMARY KEY(idconnection) ,
INDEX connection_FKIndex1(toolboxAccount_idtoolboxAccount),
FOREIGN KEY(toolboxAccount_idtoolboxAccount)
REFERENCES toolboxAccount(idtoolboxAccount)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE export (
idexport INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
connection_idconnection INT NOT NULL ,
nameOfExportZIP VARCHAR(255) NOT NULL ,
PRIMARY KEY(idexport) ,
INDEX export_FKIndex1(connection_idconnection),
FOREIGN KEY(connection_idconnection)
REFERENCES connection(idconnection)
ON DELETE CASCADE
ON UPDATE CASCADE);
The classes are
ToolboxaccountEntity
#Entity
#Table(name = "toolboxaccount", schema = "", catalog = "toolboxtest")
public class ToolboxaccountEntity {
#Id
#GeneratedValue(generator="my_seq")
#SequenceGenerator(name="my_seq",sequenceName="MY_SEQ", allocationSize=1)
private long idtoolboxAccount;
private String username;
private String password_2;
#OneToOne(cascade = CascadeType.PERSIST)
private ConfigEntity configEntity;
#OneToMany(cascade = CascadeType.PERSIST)
private List<ConnectionEntity> connections;
public List<ConnectionEntity> getConnections() {
return connections;
}
public void setConnections(List<ConnectionEntity> connections) {
this.connections = connections;
}
...
ConnectionEnity
#Entity
#Table(name = "connection", schema = "", catalog = "toolboxtest")
public class ConnectionEntity {
#Id
#GeneratedValue(generator="my_seq")
#SequenceGenerator(name="my_seq",sequenceName="MY_SEQ", allocationSize=1)
private long idconnection;
private String url;
private String username;
private String password_2;
private String site;
#Column(name = "idconnection")
public long getIdconnection() {
return idconnection;
}
public void setIdconnection(int idconnection) {
this.idconnection = idconnection;
}
...
The persisting of ToolboxAccountEntity works but when I add a ConnectionEntity I get following error:
Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`toolboxtest`.`connection`, CONSTRAINT `connection_ibfk_1` FOREIGN KEY (`toolboxAccount_idtoolboxAccount`) REFERENCES `toolboxaccount` (`idtoolboxAccount`) ON DELETE CASCADE ON UPDATE CASCADE)
Error Code: 1452
Call: INSERT INTO toolboxtest.connection (PASSWORD_2, SITE, URL, USERNAME) VALUES (?, ?, ?, ?)
bind => [4 parameters bound]
2 things:
1) If you want to make a insert operation, make sure that the record doesnt exists in the Database.
2) If you want to make an update operation, make sure that the record exist in the database.
3) Remember that the records has to be well relationships, primary key, foreign key.
That kind of error, is very common when a record already exists.
Regards! Tell us if you correct your issue
I have a table, which has a column "description" of type TEXT. If I do:
SELECT id, description FROM table_name;
I see in "description" column instead of text value a number. Is there any way to see the text value?
Edit: After some testing I found out why I see numbers, but others like Craig see real text. It's because the data are inserted using Hibernate.
Entity:
#Entity
public class Settings {
#Id
#GeneratedValue
private Integer id;
#Column(nullable = false, unique = true)
private String key;
#Lob
#Column(nullable = false, length = Integer.MAX_VALUE)
private String value;
// getters and setters
}
Log result:
Hibernate: create table Settings (id int4 not null, key varchar(255) not null, value text not null, primary key (id));
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into Settings (key, value, id) values (?, ?, ?)
16:05:32,718 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [GoogleSiteVerification]
16:05:32,718 TRACE BasicBinder:81 - binding parameter [2] as [CLOB] - []
16:05:32,726 TRACE BasicBinder:81 - binding parameter [3] as [INTEGER] - [4]
If I do in pgAdmin3 this select:
select * from settings;
I see this result:
1;"GoogleSiteVerification";"112351"
Added #Type(type = "org.hibernate.type.TextType") to attribute annotated with #Lob. Now it works as desired.
Also it solved the issue with encoding, which was the reason I opened pgAdmin in the first place (to see what's inside).
Technical detail: PostgreSQL stored LOB in separate place and referenced it by a numerical identifier (which was what the number which confused me).
Setup:
CREATE TABLE table_name (id integer, description text);
INSERT INTO table_name(id, description) values (1, '12');
Demo:
testdb=> SELECT id, description FROM table_name;
id | description
----+-------------
1 | 12
(1 row)
Yup, I'd say you have a number in your description column because there's a number in your description column.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I was faced with the below problem
problem
P.S. Have a look at the comments :) on the above link
And while solving it, I now have a question about how the unique constraint is implemented in hibernate, I have started to believe that it fires a select query (I am not sure about this), and then "some how" performs the validation.
I am not very convinced with the explanation
Hibernate creates a "unique" index on that column, and it's the database that then enforces the uniquness.
For example, if you have a class:
#Entity
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class UserEmailAddressEntity {
#Id
#Basic(optional = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Basic(optional = false)
private boolean primaryEmail;
#ManyToOne(optional = false)
private UserEntity user;
#NaturalId // this means the email column must be unique
#Basic(optional = false)
private String email;
#Basic(optional = false)
private String token;
#Basic(optional = false)
private boolean verified;
}
Hibernate creates a table like so: (for PostgreSQL, but the idea is the same for pretty much all RDBMS)
CREATE TABLE useremailaddressentity
(
id bigint NOT NULL,
email character varying(255) NOT NULL,
primaryemail boolean NOT NULL,
token character varying(255) NOT NULL,
verified boolean NOT NULL,
user_id bigint NOT NULL,
CONSTRAINT useremailaddressentity_pkey PRIMARY KEY (id),
CONSTRAINT fk279a5e06c843ec30 FOREIGN KEY (user_id)
REFERENCES userentity (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
-- note the `UNIQUE` here:
CONSTRAINT useremailaddressentity_email_key UNIQUE (email)
)
I tried to replicate this behavior , I using using grails 1.3.7 and found it to be reproducible
class Child {
String name
static constraints = { name(unique:true) }
}
table created
CREATE TABLE `child` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
)
Queries fired on
child.save()
Hibernate: select this_.id as id0_0_, this_.version as version0_0_, this_.created_by as created3_0_0_, this_.date_created as date4_0_0_, this_.last_updated as last5_0_0_, this_.name as name0_0_, this_.updated_by as updated7_0_0_ from child this_ where this_.name=?
Hibernate: insert into child (version, created_by, date_created, last_updated, name, updated_by) values (?, ?, ?, ?, ?, ?)
The reason i think i hibernate fires the above query is to check the unique constraint, And in case you are trying to perform an update then this query will result in having another object with the same identifier in memory, which could the lead to nonuniqueobjectexception.
I thinking this is hibernate and not grails, have not double checked this in java/hibernate.
Thanks
I've encountered a strange error with JPA that is not persistence provider specific. I'm using JPA 2.0 and I'm using a generated schema.
In short: The generated schema includes a join table with three columns, but the generated insert statements treat this table as if it had only two columns.
Here are the mappings:
#Entity
#Table( name = "Game" )
public class MatchEntity implements Match, Serializable {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
#ManyToOne( targetEntity = ClubEntity.class )
private Club homeTeam;
#ManyToOne( targetEntity = ClubEntity.class )
private Club awayTeam;
#ManyToMany( targetEntity = PlayerEntity.class )
private Collection<Player> homeTeamPlayers;
#ManyToMany( targetEntity = PlayerEntity.class )
private Collection<Player> awayTeamPlayers;
private String location;
#Temporal( value = TemporalType.DATE )
#Column( name = "Match_Date" )
private Date date;
/* constructor, getters and setters follow */
}
#Entity
#Table( name = "Club" )
public class ClubEntity implements Club, Serializable {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
private String name;
#OneToMany( fetch = FetchType.EAGER, targetEntity = PlayerEntity.class,
mappedBy = "club" )
private Collection<Player> players = new ArrayList<Player>();
private String fieldName;
private Boolean archived;
/* constructor, getters and setters follow */
}
#Entity
#Table( name = "PLAYER" )
public class PlayerEntity implements Player, Serializable {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
private String firstName;
private String surname;
#Temporal( value = TemporalType.DATE )
private Date birthDate;
#Column( name = "pos" )
#Enumerated( EnumType.ORDINAL )
private Position position;
private Integer number;
private Boolean archived;
#ManyToOne( targetEntity = ClubEntity.class, fetch = FetchType.EAGER )
private Club club;
/* constructor, getters and setters follow */
}
From these mappings, the following schema gets created:
create table Club (id bigint generated by default as identity (start with 1), archived bit, fieldName varchar(255) not null, name varchar(255) not null, primary key (id))
create table Game (id bigint generated by default as identity (start with 1), Match_Date date, location varchar(255), awayTeam_id bigint, homeTeam_id bigint, primary key (id))
create table Game_PLAYER (Game_id bigint not null, homeTeamPlayers_id bigint not null, awayTeamPlayers_id bigint not null)
create table PLAYER (id bigint generated by default as identity (start with 1), archived bit, birthDate date, firstName varchar(255) not null, number integer, pos integer, surname varchar(255) not null, club_id bigint, primary key (id))
alter table Game add constraint FK21C0123B2A3B9E foreign key (homeTeam_id) references Club
alter table Game add constraint FK21C012F5972EAF foreign key (awayTeam_id) references Club
alter table Game_PLAYER add constraint FK267CF3AE6AE1D889 foreign key (Game_id) references Game
alter table Game_PLAYER add constraint FK267CF3AED51EDECF foreign key (homeTeamPlayers_id) references PLAYER
alter table Game_PLAYER add constraint FK267CF3AE6CBE869E foreign key (awayTeamPlayers_id) references PLAYER
alter table PLAYER add constraint FK8CD18EE13F2C6C64 foreign key (club_id) references Club
This line is important - this is the join table.
create table Game_PLAYER (Game_id bigint not null, homeTeamPlayers_id bigint not null, awayTeamPlayers_id bigint not null)
When I try to persist the Game entity (MatchEntity.java), this happens:
insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
Hibernate: insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
binding '2' to parameter: 1
binding '1' to parameter: 2
reusing prepared statement
insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
Hibernate: insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
binding '2' to parameter: 1
binding '2' to parameter: 2
done inserting collection: 2 rows inserted
Inserting collection: [football.model.entities.MatchEntity.homeTeamPlayers#2]
Executing batch size: 2
about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
Could not execute JDBC batch update [insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)]
JPA tries to insert two rows to the join table, each affecting only two columns of the three.
What I have tried:
Getting rid of the interfaces in the mappings altogether
Defining an explicit join table
Using OpenJPA instead of Hibernate
Neither did resolve the problem.
edit: code for eager fetching:
#Transactional(readOnly = true)
public Collection<Match> findAll() {
em.createQuery("SELECT m FROM MatchEntity m "
+ "JOIN FETCH m.homeTeamPlayers", MatchEntity.class).getResultList();
List<MatchEntity> rList = em.createQuery("SELECT m FROM MatchEntity m "
+ "JOIN FETCH m.awayTeamPlayers", MatchEntity.class).getResultList();
Collection<Match> result = new ArrayList<Match>( rList );
return result;
}
Perhaps you need different join tables for homeTeamPlayers and awayTeamPlayers:
#ManyToMany( targetEntity = PlayerEntity.class )
#JoinTable(name = "Game_HomeTeamPlayers")
private Collection<Player> homeTeamPlayers;
#ManyToMany( targetEntity = PlayerEntity.class )
#JoinTable(name = "Game_AwayTeamPlayers")
private Collection<Player> awayTeamPlayers;