hibernate h2 embeddable list expected "identifier" - java

I'm trying to associate a list of function (whom Embeddable) within my Employee Entity and H2 seems unhappy with this saying that it expected an "identifier"
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "
CREATE TABLE EMPLOYEE_FUNCTIONS (
EMPLOYEE_EMPLOYEEID VARCHAR(255) NOT NULL,
ACTIVE BOOLEAN NOT NULL,
DEPARTMENTNUMBER INTEGER NOT NULL,
DESCRIPTION VARCHAR(255),
ORDER[*] INTEGER NOT NULL
) "; expected "identifier";
The thing is I already done that with an other project and I don't see why it doesn't work.
Employee.java
#Entity
public class Employee extends AbstractScheduleEntity<EmployeeSchedule> {
public static final String ACOMBA_UNIQUE_FIELD = "acombaUnique";
#Id
#GenericGenerator(name = "sequence_id", strategy =
"ca.tecsar.core.sql.ServerSequenceGenerator")
#GeneratedValue(generator = "sequence_id")
#Column(name = "EmployeeID", unique = true, nullable = false)
private String employeeID;
#ElementCollection
private List<Function> functions;
//getter and setter
}
Function.java
#Embeddable
public class Function implements Serializable {
private int order;
private boolean active;
private String description;
private int departmentNumber;
//getter and setter
}
I removed a few properties in Employee that wasn't necessary.
What may cause this error? Is it because I have a String as identifier in my Employee? If so how can I tell to Hibernate to add Employee_EmployeeID as identifier?
Thanks

Turns out I was being dumb and named a column "Order". Wonder why H2 wasn't happy :upside_down:
Changed the variable name to something else and it worked!

I have the same problem while naming the fields: private String to and private String from , changed to ex. dayTo , dayFrom , and it worked.

Got same issue with Order as entity. Changed table name to "orderz" and goes on.

I had the same problem with Spring and H2 database for tests, My entity had the field name "interval", I renamed to "inter" and resolved the problem.
So, these errors happen due to a sql reserved names in entities.

I was facing a similar issue because of a field in my entity called "interval".
The answers to this post help me identify the root cause, however changing the name of the field was not a solution for me because "interval" was perfect for my class.
The solution I used was to rename the table column by using hibernate annotation.
#Column(name = "FREQUENCY_INTERVAL")
private int interval;
This helped me keep the variable name as 'interval' while mapping to a column name that is acceptable by the database.

I also had an issue with an entity field called row as it is also a keyword
I specified a Column name ("SEAT_ROW") to get around it.
#Entity
data class Seat (
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
val id : Long,
#Column(name="SEAT_ROW")
val row : Char,
val num : Int,
val price : BigDecimal,
val description : String
) {
override fun toString(): String = "Seat $row-$num $$price ($description)"
}
H2 Compatibility and Keywords Table

I was using order as table name in h2. Changed to something like _order and I get it!
As you can see here, order is a reserved word by h2.

try to put the ; before the " and test ?

in my case problem cause was incorrect syntax in insert statement
problem :
insert into 'table name missing' (column names...) values(values...);
after adding table name
fix:
insert into 'table name specified' (column names...) values(values...);
some times trivial mistakes are hard to spot :)

I had the somewhat same problem but instead mine was missing a semi-colon.

Related

Spring Data JDBC org.springframework.data.mapping.MappingException: Could not read value rental_movie from result set

How to select query filter in one-to-one relationship with Spring Data JDBC ?
Schema looks like this, basically 2 tables where Rental references Movie
drop table if exists rental;
drop table if exists movie;
create table movie
(
id serial primary key,
title text,
description text
);
create table rental
(
movie integer primary key references movie (id),
duration text,
price integer
)
And my code looks like this
#Query("select * from movie where title = :title ")
fun findByTitle(#Param("title") title: String): List<Movie>
But got an exception org.springframework.data.mapping.MappingException: Could not read value rental_movie from result set!
The example project on GitHub.
P.S I am quite new to this and followed this video to learn basics, please help me to do it in proper way
Solution # 1
Use the #Query like this, but still not so good since there can be a lot of columns inside second table
SELECT movie.*,
rental.price AS rental_price,
rental.duration AS rental_duration,
rental.movie AS rental_movie
FROM movie
LEFT OUTER JOIN rental ON rental.movie = movie.id
where movie.title = 'Matrix'
Your solution #1 is currently the correct way to do this.
Query must return columns for all simple properties of the aggregate root, and for all embedded or referenced entities.
If you don't want to do that you can alway specify your own RowMapper or ResultSetExtractor
Let's assume the following classes (similar to those you probably have):
class Movie {
#Id Long id;
String title;
#Embedded
Actor with;
Rental rental;
}
class Actor {
String name;
}
class Rental {
Integer price;
}
Your select needs to return the following columns:
id for the id property of Movie
title for the title property of Movie
rental_price for the price property of Rental. Note the prefix rental comes from the property namerentalnot from the class nameRental`.
rental_movie this column is an artificial id for Rental used to determine if there is a Rental at all or if Movie.rental is null.
The value is irrelevant except for the fact if it is null or not.
This column is not required if Rental has an id column.
name for the property name of the class Actor.
Note: There is no prefix here. If you want a prefix, e.g. because a class is embedded multiple times you have to put that in the #Embedded annotation.
_Note #1: There is no artificial id here.
For embedded classes there is the onEmpty attribute of the #Embedded annotation to control if when all properties are null, if the whole embedded class is null or if the embedded class gets instantiated with all properties set to null.
With Spring Data JDBC 1.x a missing column causes an exception as you have seen.
From Version 2.0 a missing column will be silently ignored and the property not set.
There is an issue to provide an easier way to define by just defining the where clause: https://jira.spring.io/browse/DATAJDBC-225
data class Movie(
#Id
val id: Long?,
val title: String,
val description: String,
val rental: Rental
)
I don't use Kotlin, but I think if you want to query Movie and Rental together, you have to use #OneToOne annotation. Something like(java):
public class Movie {
#OneToOne(mappedBy = "moive", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, optional = false)
private Rental rental;
}
And your Rental class is not right, need movieId.
public class Rental {
...
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "movie_id")
private Movie movie;
}
you could check some code example.

Hibernate Envers - select "all" changes for entity ID

I have problem with Hibernate Envers.
I have classes like:
#Entity
#Table(name = "REVINFO")
#RevisionEntity(MyRevisionEntityListener.class)
public class RevEntity {
#Id
#RevisionNumber
#Column(name = "REV", nullable = false, updatable = false)
private Integer id;
#RevisionTimestamp
#Column(name = "REVTSTMP", nullable = false, updatable = false)
private Date timestamp;
#Column(name = "MODIFIED_BY", length = 100)
private String modifiedBy;
#Column(name = "COMMENT", length = 100)
private String comment;
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
RevEntity a = (RevEntity) revisionEntity;
a.setComment("Some value");
}
}
How can i select every change for entity ID and their "REVINFO" object?
I've got something like this:
List resultList = AuditReaderFactory.get(entityManager)
.createQuery()
.forRevisionsOfEntityWithChanges(ClientType.class, true)
.add(AuditEntity.id().eq(entityId))
.getResultList();
And it's almost work good. I received every "change" but REVINFO looks strange. All fields are null - and there are 1 more object $$_hibernate_interceptor which actually hold "information" but i cannot acces it via code (or i dont know how). See example at the image.
So my question is:
1 - How can i get REVINFO values ?
2 - Do i realy have to use entityManager, or can it be achived with different approach ?
Edit 2:
Correct me if i am wrong, but does forRevisionsOfEntityWithChanges works as Lazy Initialization? I mean, if i try to receive for example modifiedBy field i actually get my data. Debugger log make me confused.
The call to forRevisionsOfEntityWithChanges returns an object array that contains:
Entity instance
Revision Entity
Revision Type
Property names that were changed.
How can i get REVINFO values ? 2 - Do i realy have to use entityManager, or can it be achived with different approach ?
So in your code, to get the revision info attributes, you would do the following. Note that in this code, the type of the revision-info object will depend on your configuration or if you're using a custom revision-info entity class in your deployment. Just be sure to cast it to the proper type.
for (Object entry : resultList) {
final Object[] row = (Object[]) entry;
final TheRevisionEntityClassType revisionInfo = row[1];
// now you can get the revision entity attributes from revisionInfo using getters
}
Correct me if i am wrong, but does forRevisionsOfEntityWithChanges works as Lazy Initialization? I mean, if i try to receive for example modifiedBy field i actually get my data. Debugger log make me confused.
Depending on the query, yes Hibernate may use proxies and its important to understand that in this case, the visual representation you get in the debugger may or may not be accurate depending if the object's internal state gets initialized by the debugger window or not.

Hibernate #Filter on enum column type

This is a similar question to this: Hibernate #Filter collection of enums
But in that question it looks like the asker has an enum type of varchar on the database, which is working fine for me.
My isue is when trying to use hibernate filter annotations on entity values that have an enum column type in the database. Let's say the enum type of the column is called "database_enum"
Take entity:
#Entity
#Table(name = "table_1")
#TypeDefs(
TypeDef(name = "enum", typeClass = PostgreSQLEnumType::class)
)
#Mockable
class table1{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Int = 0
...
#Enumerated(EnumType.STRING)
#Type(type = "enum")
lateinit var enumColumn: EnumClass
}
With EnumClass:
enum class EnumClass{
TYPEA(EnumSubClass.ONE),
TYPEB(EnumSubClass.TWO),
...
TYPEN(EnumSubClass.N);
val category: EnumSubClass
constructor(category: EnumSubClass) {
this.category = category
}
companion object {
...
}
}
The filter is on a parent entity:
#Entity
#Table(name = "mla_simulation_turbine")
#FilterDefs(
FilterDef(name = "enumTypeFilter", parameters = [ParamDef(name="enumTypeParam", type="string")])
)
#Mockable
class ParentEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Int = 0
#OneToMany(mappedBy = "...", fetch = FetchType.LAZY)
#Filters(
Filter(name = "enumTypeFilter", condition="enumColumn= :enumTypeParam")
)
var components = mutableSetOf<EnumClass>()
}
And the filter being set like this:
val existingSession = em.unwrap(Session::class.java)
existingSession.enableFilter("enumTypeFilter")
.setParameter("enumTypeParam", EnumClass.TYPEA.toString())
The query in hibernate logging shows the filter as:
SELECT ...
where
enum_column.enum_type= ?
Finally the exception raised when I load the enum entity is an SQLGrammarException caused by:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: database_enum= character varying
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 925
I'm wondering if I need to refactor things and just keep the enum on the kotlin side and give it a varchar type in the database. I have not been able to find a similar post/issue with any helpful answers but here is what I have looked at:
https://forum.hibernate.org/viewtopic.php?f=1&t=1044249&view=previous
hibernate criteria filtering on a set of enum values
and a few others.
Any help or tips here would be appreciated. Thanks!
Ok, got the solution for anyone that could benefit from it.
You need to cast the column to text rather than cast the parameters to enum....
cast(enumColumn as text) in (:enumTypeParam)
Works like a charm.

JPA Mapping Multi-Rows with ElementCollection

I'm trying to follow the JPA tutorial and using ElementCollection to record employee phone numbers:
PHONE (table)
OWNER_ID TYPE NUMBER
1 home 792-0001
1 work 494-1234
2 work 892-0005
Short version
What I need is a class like this:
#Entity
#Table(name="Phones")
public class PhoneId {
#Id
#Column(name="owner_id")
long owner_id;
#Embedded
List<Phone> phones;
}
that stores each person's phone numbers in a collection.
Long version
I follow the tutorial code:
#Entity
#Table(name="Phones")
public class PhoneId {
#Id
#Column(name="owner_id")
long owner_id;
#ElementCollection
#CollectionTable(
name="Phones",
joinColumns=#JoinColumn(name="owner_id")
)
List<Phone> phones = new ArrayList<Phone>();
}
#Embeddable
class Phone {
#Column(name="type")
String type = "";
#Column(name="number")
String number = "";
public Phone () {}
public Phone (String type, String number)
{ this.type = type; this.number = number; }
}
with a slight difference that I only keep one table. I tried to use the following code to add records to this table:
public static void main (String[] args) {
EntityManagerFactory entityFactory =
Persistence.createEntityManagerFactory("Tutorial");
EntityManager entityManager = entityFactory.createEntityManager();
// Create new entity
entityManager.getTransaction().begin();
Phone ph = new Phone("home", "001-010-0100");
PhoneId phid = new PhoneId();
phid.phones.add(ph);
entityManager.persist(phid);
entityManager.getTransaction().commit();
entityManager.close();
}
but it keeps throwing exceptions
Internal Exception: org.postgresql.util.PSQLException: ERROR: null
value in column "type" violates not-null constraint Detail: Failing
row contains (0, null, null). Error Code: 0 Call: INSERT INTO Phones
(owner_id) VALUES (?) bind => [1 parameter bound] Query:
InsertObjectQuery(tutorial.Phone1#162e295)
What did I do wrong?
Sadly, i think the slight difference that you only keep one table is the problem here.
Look at the declaration of the PhoneId class (which i would suggest is better called PhoneOwner or something like that):
#Entity
#Table(name="Phones")
public class PhoneId {
When you declare that a class is an entity mapped to a certain table, you are making a set of assertions, of which two are particularly important here. Firstly, that there is one row in the table for each instance of the entity, and vice versa. Secondly, that there is one column in the table for each scalar field of the entity, and vice versa. Both of these are at the heart of the idea of object-relational mapping.
However, in your schema, neither of these assertions hold. In the data you gave:
OWNER_ID TYPE NUMBER
1 home 792-0001
1 work 494-1234
2 work 892-0005
There are two rows corresponding to the entity with owner_id 1, violating the first assertion. There are columns TYPE and NUMBER which are not mapped to fields in the entity, violating the second assertion.
(To be clear, there is nothing wrong with your declaration of the Phone class or the phones field - just the PhoneId entity)
As a result, when your JPA provider tries to insert an instance of PhoneId into the database, it runs into trouble. Because there are no mappings for the TYPE and NUMBER columns in PhoneId, when it generates the SQL for the insert, it does not include values for them. This is why you get the error you see - the provider writes INSERT INTO Phones (owner_id) VALUES (?), which PostgreSQL treats as INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null), which is rejected.
Even if you did manage to insert a row into this table, you would then run into trouble on retrieving an object from it. Say you asked for the instance of PhoneId with owner_id 1. The provider would write SQL amounting to select * from Phones where owner_id = 1, and it would expect that to find exactly one row, which it can map to an object. But it will find two rows!
The solution, i'm afraid, is to use two tables, one for PhoneId, and one for Phone. The table for PhoneId will be trivially simple, but it is necessary for the correct operation of the JPA machinery.
Assuming you rename PhoneId to PhoneOwner, the tables need to look like:
create table PhoneOwner (
owner_id integer primary key
)
create table Phone (
owner_id integer not null references PhoneOwner,
type varchar(255) not null,
number varchar(255) not null,
primary key (owner_id, number)
)
(I've made (owner_id, number) the primary key for Phone, on the assumption that one owner might have more than one number of a given type, but will never have one number recorded under two types. You might prefer (owner_id, type) if that better reflects your domain.)
The entities are then:
#Entity
#Table(name="PhoneOwner")
public class PhoneOwner {
#Id
#Column(name="owner_id")
long id;
#ElementCollection
#CollectionTable(name = "Phone", joinColumns = #JoinColumn(name = "owner_id"))
List<Phone> phones = new ArrayList<Phone>();
}
#Embeddable
class Phone {
#Column(name="type", nullable = false)
String type;
#Column(name="number", nullable = false)
String number;
}
Now, if you really don't want to introduce a table for the PhoneOwner, then you might be able to get out of it using a view. Like this:
create view PhoneOwner as select distinct owner_id from Phone;
As far as the JPA provider can tell, this is a table, and it will support the queries it needs to do to read data.
However, it won't support inserts. If you ever needed to add a phone for an owner who is not currently in the database, you would need to go round the back and insert a row directly into Phone. Not very nice.

#OneToOne-Relation with "is not null"

I'm using JPA2, Unitils, jUnit + other stuff.
My problem concerns two entities:
#Entity
public class CaseStuff implements Serializable {
....
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long caseStuffId;
#OneToOne(mappedBy = "CaseStuff")
private XCase xcase;
...
}
#Entity
public class XCase implements Serializable {
....
#OneToOne
#JoinColumn(name = "CASESTUFFID")
private CaseStuff caseStuff;
....
}
Both tables got the ID of the other table, so it could also be mapped the other way around.
In a jUnit-Test, Unitils inserts one CaseStuff record with no XCase. I confirmed, that it really is null.
BUT, then I use the following query:
"select s from CaseStuff s where s.xcase is null"
and it returns 0 CaseStuff objects. Doing the same with "is not null" returns the object, but when inspecting CaseStuff.xcase while debugging, it is clearly null.
Any idea, what's going awry here?
EDIT:
The SQL generated by Hibernate translates to
select
*
from
CaseStuff casestuff0_
where
(
casestuff0_.xcaseid is null
)
*Replaced all field names by *
EDIT2:
Before I changed it to a OneToOne-Relation, it was an unneccessary ManyToOne.
Previously the jUnit test had the query
"select s from CaseStuff s where not exists (select x from s.xcase x)"
This still works correctly for some reason, as if s.xcase was still a Set.
Thanks to all who try to figure it out with me.
As you defined your entities Xcase will have the foreign key
So Xcase table beside it's id will have caseStuff_id (or other name) as foreign key to the Xcase id.
Like in this image (make abstraction of the names)
In your case Person is Xcase and CaseStuff is PersonDetails
So probably you CaseStuff table (if it was generated by the persistence provider does not have a case id)
Please check on the db level to see how your tables are defined, structurally speaking.

Categories