Hibernate create table with name escaped - java

I have a Entity class like the following:
#Entity
public class perm {
#Id
#GeneratedValue
private Long id;
private boolean add;
// Getter & Setter are also there ...
}
When I start spring (with JPA hibernate), he generates the following CREATE TABLE statement for my MySQL database:
create table perm (id bigint not null auto_increment, add bit not null, primary key (id))
This create will fail, because the column name add is not escaped with
`
like it normally should be.
Normally I would create it manually with the following code:
create table perm (`id` bigint not null auto_increment, `add` bit not null, primary key (`id`))
Of course I could create a ImprovedNamingStrategy in order to manipulate all the column names by setting a prefix or suffix to them. But then all my columns have this syntax.
Now my question:
Is there maybe a jpaProperty that escapes a column name, everytime it is used inside a sql syntax? At first I thought, that this will already be done, when I set my
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");`
But apparently this is not the case. Maybe there is another setting for this?

Add #Column annotation to the field:
#Entity
public class perm {
#Id
#GeneratedValue
private Long id;
#Column(name="`add`")
private boolean add;
// Getter & Setter are also there ...
}
Also consider using a better name for the column. This may cause problems somewhere else.

add is a reserved keyword in Mysql as you can see here https://dev.mysql.com/doc/refman/5.7/en/keywords.html
You are better to avoid using it. Using isAdded may be an alternative.
In case you cannot change the column name, use this to instruct Hibernate:
#Column(name="[add]")
private boolean add;

Related

Mapping recursive relation via secondary table with Spring Data

I have database such as this:
CREATE TABLE unit
(
id INTEGER NOT NULL,
name VARCHAR,
);
CREATE TABLE unit_composition
(
parent_id INTEGER NOT NULL,
child_id INTEGER NOT NULL,
quantity INTEGER,
CONSTRAINT child_fk FOREIGN KEY (parent_id)
REFERENCES public.refdse (id) MATCH SIMPLE,
CONSTRAINT parent_fk FOREIGN KEY (parent_id)
REFERENCES public.refdse (id) MATCH SIMPLE
);
ALTER TABLE unit_composition
ADD CONSTRAINT composit_pk PRIMARY KEY (parent_id, art_nr);
I have a table of manufactory units. Each unit can have multiple sub-units, and sub-units can have multiple sub-sub-units and so on. Also I have a quantity field that shows how many sub-units are needed to manufactor a single unit. So it is kind of a tree relation.
Now I want to map it to classes with Spring Data. I have a Unit class with an Id and Name:
#Entity
#Table(name = "unit")
class Unit {
#Id
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
...
}
I've created a secondary class Part:
class Part {
private Unit unit;
private int quantity;
...
}
And I need unit class to have a field like List subUnits.
I tried to do it with a #SecondaryTable and #JoinColumn annotations, but I got an error saying "Relation unit_unit does not exist".
Also I tried to make Part an #Entity but it has no Id field.
Alternatively I tried to make #Embeddable class PartId and insert an instance into Part class like this:
#Embeddable
public class PartId implements Serializable {
private Unit parentUnit;
private Unit unit;
I'm getting an error in PartId class saying that "Basic type should not be Persistence Entity" because it's Embeddable and don't have a table assign to it.
So how can I make this work being able to get recursivly all sub-units (with sub-sub-units and so on) of a given Unit? I don't quite get it how can I map an entity that is really just links from table to itself.
So my first solution was to make Jdbc template repository and simply build necessary lists manually via SQL-queries. But I found much better and simplier solution that required adding an id column to unit_composition table and therefore making Part class an #Entity with #ManyToOne relationship to a Unit class. And the rest was simply done by Spring Data.

Schema-validation: missing table [...] error message using flyway for a SQL code generated by Hibernate

I've been trying to deal with some problems regarding Flyway. My situation is the following: I have two Java classes, which I'd like to migrate as two schemas. Let's name them Table and CustomTable. My java classes look like:
#Entity
public class xtable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
//getters, setters, constructors
#Entity
public class CustomTable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String a;
private String b;
private String c;
//getters, setters, constructors
My application.properties:
spring.flyway.url=${env.var1}
spring.flyway.user=${env.var2}
spring.flyway.password=${env.var3}
spring.jpa.hibernate.ddl-auto=validate
//If I use create-drop, hibernate creates it, but after that the validation fails
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.logging.level.org.hibernate.SQL=debug
spring.jpa.show-sql=true
hibernate.temp.use_jdbc_metadata_defaults=true
spring.flyway.enabled=true
My build.gradle:
plugins {
id "org.flywaydb.flyway" version "5.2.4"
}
dependencies {
implementation 'org.flywaydb:flyway-core'
}
The situation is so weird, because it does not even work with the auto-generated SQL code, which I let the program create without flyway.
It looks like this:
create table custom_table (
id bigint not null,
a varchar(255),
b varchar(255),
c varchar(255),
xtable_id bigint,
primary key (id)
)
engine = InnoDB;
create table xtable (
id bigint not null,
name varchar(255),
xtable_id bigint,
primary key (id)
)
engine = InnoDB;
alter table custom_table
add constraint FKep6vooglihwraille12muox9 foreign key (xtable_id) references xtable (id);
alter table xtable
add constraint FK426q765pr4gv5wux6jaktafqk foreign key (custom_table_id) references custom_table (id);
I also don't understand why Hibernate creates one-one foreign key into each class, but the bigger problem is that I still get the error message
Schema-validation: missing table [custom_table]
I tried renaming custom_table to customtable (and also renaming the class in Java), but the error message was the same.
Have you ever met the same problem? Have you got any suggestions? I've been working on this problem for - at least - 2 days.
I looked for relevant - or seemingly identical - topics here, but I couldn't find a good solution.
Thank you.
Finally I got the problem. The problem was with inserting multiple foreign keys. (So these two lines):
alter table custom_table
add constraint FKep6vooglihwraille12muox9 foreign key (xtable_id) references xtable (id);
alter table xtable
add constraint FK426q765pr4gv5wux6jaktafqk foreign key (custom_table_id) references custom_table (id);
I couldn't figure out, though, the reason why Flyway couldn't handle this, but when I recreated the whole structure with the two tables and another one containing the proper ID's, doing exactly the same thing in the whole project, it worked.

Default value declared in JPA #Column( columnDefinition ... ) not set when persisted

I have attribute in my Java entity like this:
#Basic(fetch = FetchType.LAZY) //I tried without this as well
#Column(name = "value_x", columnDefinition = "bigint default 0")
private Long valueX;
In table definition in pgAdmin I see:
value_x bigint DEFAULT 0,
but when object is inserted (with this attribute as null), column is empty/null not having 0 value inserted.
Anyone would know why it does not insert the default value? Using EclipseLink.
Null value is because JPA explicitly inserts a null value in to that column if no special handling is implemented. The columnDefinition does make the column creation with DEFAULT but it does not make JPA aware of/or obey it afterwards.
And it is a nullable column so there is no error. See what happens in plain SQL, think of this table:
create table example (
col1 bigint default 42,
col2 bigint default 99
);
Then make an insert like:
insert into example (col1) values (null);
then selecting:
select * from example;
would show result like:
col1 | col2
------+------
(null) | 99
If you need to have default values managed in the java side you need some special stuff in the Java side.
See for example this question and note that the accepted answer is not the working one but this answer. So setting the value when class is instantiated:
private Long valueX = 0;
Another way is as this answer for different question suggests, using #PrePersist:
#PrePersist
void prePersist() {
if (this.valueX == null)
this.valueX = 0;
}
I found another way to resolve the same problem, because when I create my own object and persist in database and didnĀ“t respect the DDL with default value.
So I looked at my console, and the SQL generated, and saw that insert came with all fields, but only one propertie in my object has the value changed.
So I put in the model class this annotation.
#DynamicInsert
When is inserting data, the framework not insert null values or values that are not modified, making the insert shorter.
Also has #DynamicUpdate annotation.

Manually update the counter used for generation of primary key in Hibernate?

In my spring project, the tables in database are created automatically by Hibernate using my entity classes as base, but I insert some default values in the table manually (using pgAdmin3).
Because that, I am facing now this problem: when I try insert a value via Java code in one of the tables which already have values, I receive a error message, saying the primary key already exists in the database.
Anyone knows how to solve this problem?
UPDATE
That's how I declare my primary key in my class:
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
Call this SQL query once per table to set the sequence to the next free number:
SELECT setval('tblname_id_seq', max(id)) FROM tblname;
tblname being the actual name of the table.
Hibernate may use a different naming convention, or the sequence may have been renamed. If you can't find the sequence behind the serial column, check with (per documentation):
SELECT pg_get_serial_sequence(tblname, column_name)
More details:
Modify Django AutoField start value
How to import a CSV to postgresql that already has ID's assigned?
The problem here might be that you declare the id as a primitive instead of a wrapper.
So instead of:
private int id;
You should have:
private Integer id;
When you create the entity with the id is initialized as 0, instead of NULL.
That's why you get duplicate id constraint violation exceptions.
Only when the id is NULL the AUTO generation strategy will delegate the id assignment to the database.

JPA 2: how to declare primary-key columns in #ElementCollection tables

in JPA2 when we are using Embed-able (Basic Type like String.. etc ) object in Entity using with #ElementCollection and #CollectionTable annotation , the new table is created , but in new table how to declare primary-key contraint in column ? following is my code
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String salary;
#Transient
private String phnNum;
#Enumerated(EnumType.STRING)
private EmployeeType type;
#ElementCollection
#CollectionTable(name="vacations" , joinColumns=#JoinColumn(name="Emp_Id"))
private Collection<Vacation> vacationBooking;
#ElementCollection
private Set<String> nickNames;
...................
with this code the "vacation" and "employee_nickname" two tables are created in schema. but i want to declare the one primary-key column in both table . what i do for this?
It looks like a primary key per se is not supported by JPA 2.0:
From Wikibooks:
The JPA 2.0 specification does not provide a way to define the Id in the Embeddable. However, to delete or update an element of the ElementCollection mapping, some unique key is normally required. Otherwise, on every update the JPA provider would need to delete everything from the CollectionTable for the Entity, and then insert the values back. So, the JPA provider will most likely assume that the combination of all of the fields in the Embeddable are unique, in combination with the foreign key (JoinColumn(s)). This however could be inefficient, or just not feasible if the Embeddable is big, or complex.
Some JPA providers may allow the Id to be specified in the Embeddable, to resolve this issue. Note in this case the Id only needs to be unique for the collection, not the table, as the foreign key is included. Some may also allow the unique option on the CollectionTable to be used for this. Otherwise, if your Embeddable is complex, you may consider making it an Entity and use a OneToMany instead.
Do you mean that you want to assign 'id' from Employee table as foreign key to the Vacation table?
In that case, you should use #OneToMany instead of #ElementCollection

Categories

Resources