I have an entity that is defined with JPA annotations (only a few fields of interest shown here)
#Entity
public class Rule implements Serializable, Cloneable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO,
generator = "SEQ_STORE")
#Column(name = "RULE_ID",
nullable = false)
private final Long id = null;
#Column(name = "CODE",
length = 25,
nullable = false)
private String code;
#Column(name = "DESCRIPTION",
length = 250,
nullable = true)
private String description;
#Column(name = "VALIDATION_FIELDS",
length = 250,
nullable = true)
private String validationFields;
#ExportField("EXPRESSION")
#Lob
#Column(name = "EXPRESSION",
nullable = true)
private String expression;
#Lob
#Column(name = "ACTION",
nullable = true)
private String action;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "PARENT_ID",
nullable = true,
foreignKey = #ForeignKey(name = "FK_XTB_RULE_2_PARENT") )
private Rule parent;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "RULESET_ID",
nullable = false,
foreignKey = #ForeignKey(name = "FK_XTB_RULE_2_RULESET") )
private RuleSet ruleSet;
}
#Entity
public class RuleSet implements Serializable, Cloneable
{
private static final long serialVersionUID = 7982682149517239983L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO,
generator = "SEQ_STORE")
#ExportField("RULESET_ID")
#Column(name = "RULESET_ID",
nullable = false)
private final Long id = null;
#JsonIgnore
#OneToMany(mappedBy = "ruleSet",
fetch = FetchType.EAGER,
cascade = CascadeType.ALL)
#OrderBy("position")
private List<Rule> rules = new LinkedList<Rule>();
}
Then I have a method that generates a tree of these Rules (see the backreference) and puts all the rules into the List contained in the Ruleset entity.
The auto-generated DDL makes columns suitable for large expressions as the column is #Lob annotated
On Mysql and Oracle I can successfully run the code that populates the rules table (I run Bamboo tests that create DB from scratch every time). Hoever, when the testing is run oh HSQLDB, Hibernate's insert of the Ruleset object fails
2016-04-29 13:09:26,946 WARN [localhost-startStop-1] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - logExceptions - SQL Error: 3401, SQLState: 22001
2016-04-29 13:09:26,949 ERROR [localhost-startStop-1] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - logExceptions - data exception: string data, right truncation; table: XTB_RULES column: EXPRESSION
2016-04-29 13:09:39,965 ERROR [localhost-startStop-1] it.phoenix.web.data.managers.spring.ModuleManagerImpl - init - could not execute statement
org.hibernate.exception.DataException: could not execute statement
...
Caused by: org.hsqldb.HsqlException: data exception: string data, right truncation; table: XTB_RULES column: EXPRESSION
...
Caused by: org.hsqldb.HsqlException: data exception: string data, right truncation
There is an expression long 353 character in my code, I have almost found the "guilty" object.
But the problem is that even with HSQLDB the following DDL is generated
create table XTB_RULE_FUNCTIONS (RULE_FUNCTION_ID bigint identity not null,
DESCRIPTION varchar(250),
ENABLED bit not null,
EXPRESSION varchar(MAX) not null,
NAME varchar(50) not null,
OBJECT_TYPE varchar(20) not null,
POSITION bigint not null,
primary key (RULE_FUNCTION_ID));
EXPRESSION is supposed to be VARCHAR(max), so it should accommodate any string.
But my insertion still fails. I have no mean to check the actual in-memory database at the moment
Other info on the application:
Is a web application running on Tomcat
I use Bamboo CI to run tests on different databases, each loading the Spring context instead of being run in a servlet container
Part of Spring initialization is to populate, along others, the Ruleset table if data does not exist. Since Bamboo recreates DB at every run (especially in-memory one), I always need to populate rules declared programmatically somewhere in a piece of code useless to paste here
I have read this but I have checked that DDL script declares VARCHAR(max) so I don't think that applies to me
Again and again, the same code works on other DBs
Still, I need to store data larger than 255 characters
Any idea on how to fix? In my unit testing I may still comment out one of the entities, but that is only a workaround.
Related
#Entity
#Table(name = "Country")
#SQLDelete(sql = "UPDATE Country SET date_deleted=NOW() WHERE code = ?")
#Where(clause = "date_deleted is NULL")
public class Country {
#Id
#Column(name = "code", nullable = false)
private String code;
#Column(name = "description")
private String description;
#Column(name = "date_deleted")
private Date date_deleted;
....
}
When I logic delete an Entity in the database with the code 'U1' and after, I created a new Entity with the same code 'Ü1', occurs an exception "duplicate entry". Has Hibernate an annotation to solve this problem?
edit:
The Error when I insert a new entity with the same code is this:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates
unique constraint "country_pkey" Detail: Key (code)=(AA) already
exists.
The table is:
CREATE TABLE public.country(
code bpchar(2) NOT NULL,
description bpchar(50) NULL,
date_deleted timestamp NULL,
CONSTRAINT country_pkey PRIMARY KEY (code),
CONSTRAINT constraint_country UNIQUE (date_deleted, code) -- I add this constraint
);
Since you manage the code column and you can have multiple entries with the same code, one solution would be to have an id column that is autogenerated.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
This will enable you to delete an object with the code 'U1' and add another one with the same code.
You can check this great tutorial: https://vladmihalcea.com/the-best-way-to-soft-delete-with-hibernate/
I am currently working on a Java project with Hibernate entities (more below). In order to test my data access object layers, I am using H2 database to populate an in-memory database and throwing queries at it. Until this point, everything is fine.
However, the problem comes when simulating the #EmbeddedId annotation.
#Entity
#Table(name = "BSCOBJ")
public class BasicObject extends AbstractDomainObject {
#EmbeddedId // This annotation here
private RestrainPK restrain;
#Embeddable
public static class RestrainPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "CODI", nullable = false)
private String coDi;
#Column(name = "COGA", nullable = false)
private String coGa;
#Column(name = "TYOR", nullable = false)
private String tyOr;
public RestrainPK() {
}
... // Getters and setters
}
}
"Simply" creating the table BSCOBJ and populating it gives no value when fetching data (of course, I checked that the request would give result "normally"). How do I represent this nested class in a SQL table creation / value insertion request ? Is that even possible ?
Thanks in advance,
EDIT
As requested, here is some samples about the SQL / Hibernate ran.
Creation request:
CREATE TABLE BSCOBJ (CODI VARCHAR(5) NOT NULL, COGA VARCHAR(5) NOT NULL, TYOR VARCHAR(5) NOT NULL);
Insertion request:
INSERT INTO BSCOBJ (CODI, COGA, TYOR) VALUES
('HELLO', 'MAT', 'REF'),
('BONJ', 'SOME', 'DAIL'),
('SOPA', 'KDA', 'RATIO');
Request given by Hibernate when trying to run the test code:
select r.restrain.tyOr from mypackage.BasicObject r where r.restrain.coDi = :coDi and r.restrain.coGa = :coGa
With the following values:
coDi = "BONJ";
coGa = "SOME";
Throws a NoResultException. I am expecting DAIL, from the second line of the INSERT request.
I have used #EmbeddedId only one time, but I think that you need #AttributeOverrides under your #EmbeddedId
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "idpk", column = #Column(name="IDPK", nullable = false),
#AttributeOverride(name = "code", column = #Column(name="CODE")
})
and remove your #Column annotations from FormulePK
I add to my Entity
#Version
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version")
private Date version;
and something strange happend. When i update, hibernate tells thath key already exists. How #version filed affect my Entity? I have no idea why it happend. When i remove this #version field everything works. I also use #Audited annotation.
My Entity:
private static final long serialVersionUID = 1636824190907788517L;
#Id
#NotNull
#Column(name = "id")
private UUID id;
#Version
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version")
private Date version;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "user", nullable = false)
private User user;
#Column(name = "purpose", length = 100)
protected String comment;
#OneToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "eq_id", nullable = false)
protected BasicEquipment equip;
#OneToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "eq_id2", nullable = false)
protected BasicEquipment equip2;
Error:
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement (...)
org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(Standaorg.hibernate.engine.jdbc.sporg.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatch
org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTra
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pk_entity"
Did you try this solution?
http://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking
Under some circumstances, problems may occur when versioned updates
are used together with batch updates. It has happened to me in the
past with a given version of Oracle 11g and Hibernate, for example.
The Oracle JDBC driver was not able to extract the correct number of
updated rows count in JDBC batch statements execution.
If you are also facing this problem, you may check if you have set the
Hibernate property hibernate.jdbc.batch_versioned_data to true. When
this setting is true, Hibernate will use batch updates even for
updates that are made against versioned data, ie. updates that need to
use the updated rows count in order to check for concurrent updates.
Since the JDBC driver may not return the correct updated rows count,
Hibernate will not be able to detect if concurrent updates actually
happened. The default value for this setting in Hibernate is false, so
it will not use batch updates when it detects that versioned data
updates are going to be executed in a given flush operation.
This is of course a specific scenario with Oracle 11g that is easily
worked around, as we have just seen.
I'm building an application based on JavaEE7 with JPA 2.1 and EJB 3.2.
I'm trying to define entity with JPA based on the table from an Oracle database. I use EclipseLink as implementation of JPA.
My case is to retrieve translation stored on the database. All the translation are stored on a single table and identified with a key and a language id.
I can't change the way the database is organised and I'm a beginner in JPA.
Here an example of lines from the translation table:
TRANSLATION:
TRANS_ID | TRANS_KEY | TRANS_VALUE | LAN_ID
1 | APPVERSION_APPV_COMMENT_1215 | Du texte | 1
2 | APPVERSION_APPV_COMMENT_1215 | Some text | 2
Where LAN_ID : 1 correspond to the french translation and LAN_ID : 2 is the english translation.
The entity of TRANSLATION looks like this:
#Entity
#Table(name = "TRANSLATION")
#NamedQueries({
#NamedQuery(name="Translation.findAll", query="SELECT trans FROM Translation trans")
})
public class Translation implements Serializable {
#Id
#Column(name = "TRANS_ID", nullable = false)
private Integer translationId;
#Column(name = "TRANS_KEY", nullable = false)
private String translationKey;
#Column(name = "TRANS_VALUE")
private String translationValue;
#Column(name = "LAN_ID", nullable = false)
private Integer languageId;
}
And here is a possible case for a table using translations:
APPVERSION :
APPV_ID | APPV_COMMENT
0 | APPVERSION_APPV_COMMENT_1215
1 | (null)
2 | some texte with no reference to translation table
Here are the tree possible case I can have in column witch use translation. The third case is due to historical reasons.
I would like to implement a JPA entity to represent the table APPVERSION where I could retrieve the translation without using JPQL.
I tried an entity looking like this (simplified version):
#Entity
#Table(name = "APPVERSION")
#NamedQueries({
#NamedQuery(name="AppVersion.findAll", query="SELECT app FROM AppVersion app")
})
public class AppVersion implements Serializable {
#Id
#Column(name = "APPV_ID", nullable = false)
private Integer applicationVersionId;
#OneToMany()
#JoinColumn(name = "TRANS_KEY", referencedColumnName = "APPV_COMMENT", nullable = true)
//As a beginer who don't get it all I also tryed the following. With quite the same result
//#JoinColumn(name = "APPV_COMMENT", referencedColumnName = "TRANS_KEY", nullable = true)
private List<Translation> applicationVersionComment;
}
With, the following
#JoinColumn(name = "TRANS_KEY", referencedColumnName = "APPV_COMMENT", nullable = true)
I got an error saying:
Caused By: Exception [EclipseLink-6094] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.QueryException
Exception Description: The parameter name [APPV_COMMENT] in the query's selection criteria does not match any parameter name defined in the query.
And with the following
#JoinColumn(name = "APPV_COMMENT", referencedColumnName = "TRANS_KEY", nullable = true)
I got an error saying:
Caused By: Exception [EclipseLink-6094] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.QueryException
Exception Description: The parameter name [TRANS_KEY] in the query's selection criteria does not match any parameter name defined in the query.
I would like to know how to handle such case with JPA entity. For historical reason the data are quite messy and sadly I have to deal with it as it is.
Why if i run this code:
Student st = new Student();
st.setFirstName("First");
st.setLastName("Last");
st.setIndexNr("11");
st.setStudentPK(new StudentPK(0, user.getIdUser()));
studentFacade.create(st);
Mail m = new Mail();
m.setContent("con");
m.setRecipient("rec");
m.setIdMail(0);
mailFacade.create(m);
List<Mail> l = new ArrayList<Mail>();
l.add(m);
st.setMailList(l);
studentFacade.edit(st); // st have mailList property set to l
stud=studentFacade.findByIndex("11"); //after edit and get student he has mailList equal null
Why after persist and edit object i get null at property for OneToMany relationship?
In database MySql i have STUDENT table and MAIL table:
CREATE TABLE IF NOT EXISTS `STUDENT` (
`id_student` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT ,
`first_name` VARCHAR(65) NULL ,
`last_name` VARCHAR(65) NULL ,
`index_nr` VARCHAR(45) NULL
)
ENGINE = InnoDB
CREATE TABLE IF NOT EXISTS `MAIL` (
`id_mail` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`recipient` TEXT NULL ,
`content` TEXT NULL ,
`sender_student` MEDIUMINT UNSIGNED NULL ,
PRIMARY KEY (`id_mail`) ,
INDEX `fk_STUDENT_id_idx` (`sender_student` ASC) ,
CONSTRAINT `fk_STUDENT`
FOREIGN KEY (`sender_student` )
REFERENCES `jkitaj`.`STUDENT` (`id_student` )
ON DELETE CASCADE
ON UPDATE CASCADE
)
ENGINE = InnoDB
From database i generate entity in netbeans:
#Entity
#Table(name = "STUDENT")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected StudentPK studentPK;
#Size(max = 65)
#Column(name = "first_name")
private String firstName;
#Size(max = 65)
#Column(name = "last_name")
private String lastName;
#Size(max = 45)
#Column(name = "index_nr")
private String indexNr;
#OneToMany(mappedBy = "senderStudent",fetch=FetchType.EAGER)
private List<Mail> mailList;
//getters, setters ...
}
public class Mail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Basic(optional = false)
#Column(name = " id_mail")
private Integer idMail;
#Lob
#Size(max = 65535)
#Column(name = "recipient")
private String recipient;
#Lob
#Size(max = 65535)
#Column(name = "content")
private String content;
#JoinColumn(name = "sender_student", referencedColumnName = "id_student")
#ManyToOne
private Student senderStudent;
//getters, setters...
}
EDIT:
I think i forget about fetch in #OneToMany annotation of Student entity. But when i set in to fetch=FetchType.LAZY i again get null after edit and and get edited object from database. When set fetch=FetchType.EAGER mailList field isn't null. Why ?
Problem is at OpenJPA, when i use fetch=FetchType.LAZY at some property of entity. The problem was with life cycle of enties. All enties must be re-attached to the persistence context.
Same problem is here: OpenJPA - lazy fetching does not work and here: What's the lazy strategy and how does it work?
You have a unique combination of too much information with too little.
If you are actually running that code, then package it up as a complete, runnable example -- yes, it won't run on another machine unless that machine also has a database setup, but it will tell us everything you're doing instead of just the part that you think is important.
Give us the complete error message, don't tell us what it is.
Two important things to remember about posting a question on a site like this: you don't know what's wrong, so you need to give us complete raw data, not half-analysis. And it is generally a waste of time for us to just guess at things.