I'm using Spring Boot 1.3.3.RELEASE. By default Spring Boot uses the Hibernate Version 4.x. I'm trying to use new Hibernate i.e 5.1.0 FINAL (as of now).
I'm using Gradle so to override the Hibernate Version I've added the following line
ext['hibernate.version']="5.1.0.Final"
followed the steps of SpringBoot 1.3.0 support hibernate 5?
I'm using following for naming Strategy
spring.jpa.properties.hibernate.naming.implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
spring.jpa.properties.hibernate.naming.physical_strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
I've have a Entity class
#Entity
public class AppUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Length(max = 100)
private String username;
#NotNull
#Length(max = 100)
private String firstName;
#NotNull
#Length(max = 100)
private String lastName;
#Length(max = 100)
private String middleName;
#NotNull
#Length(max=100)
private String email;
#NotNull
#Length(max = 100)
private String password;
#NotNull
private boolean enabled;
}
On Hibernate 4.x it executes the query
create table app_user (
id bigint not null auto_increment,
email varchar(100) not null,
enabled bit not null,
first_name varchar(100) not null,
last_name varchar(100) not null,
middle_name varchar(100),
password varchar(100) not null,
username varchar(100) not null,
primary key (id)
)
on 5.x it executed the query
create table AppUser (
id bigint not null auto_increment,
email varchar(100) not null,
enabled bit not null,
firstName varchar(100) not null,
lastName varchar(100) not null,
middleName varchar(100),
password varchar(100) not null,
username varchar(100) not null,
primary key (id)
)
How can I set the naming strategy such that Hibernate Uses 5.x underscore (as 4.x) on Table name and Column Name
Firstly, you don't need
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
because of it does nothing and is used by Hibernate as default.
Hibernate 5 doesn't have a strategy that you want. All strategies are JPA compliant (generate names like AppUser). So you need to implement your own.
For an example a physical naming strategy
public class UnderscorePhysicalStartegy extends PhysicalNamingStrategyStandardImpl {
#Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return context.getIdentifierHelper()
.toIdentifier(NamingStrategyUtils.classToName(name.getText()));
}
}
It uses NamingStrategyUtils.
Keep in mind, if you specify an explicit name
#Entity
#Table(name = "AppUser")
public class AppUser {
}
you will have anyway a table name app_user. If you don't want such behavior use an implicit naming strategy.
I did some research work on naming strategies. You can refer Hibernate5NamingStrategy, it generates table and column names with underscores like you need and constraint names (unique, foreign key) as well.
This class is used to generate names: HibernateNamingStrategy.
How to use Hibernate5NamingStrategy
The naming strategy can be configured using StrategyOptions.
For example, to use strategy without the prefixes (like f_):
StrategyOptions options = StrategyOptions.builder().withoutPrefixes().build();
Hibernate5NamingStrategy strategy = new Hibernate5NamingStrategy(options);
Other examples: Hibernate 5 Implicit Naming Strategy
Except that, ImprovedNamingStrategy for Hibernate 5 can be used to simulate the behaviour of Hibernate 4 ImprovedNamingStrategy.
I am providing my analysis for anyone to use:
If you are providing #Table and #Column annotation in your entity classes with names provided with an underscore i.e. user_id i.e. #Column(name="user_id"), it will take the column name as user_id; if you give it as userid then it will change to user_id if you use no strategy or implicit strategy (specifically spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl). So, if you want a strategy where the entity attribute name changes to one with underscore and lowercase letters i.e. something from userId to user_id, you should use implicit or no strategy (which actually uses implicit strategy).
If you don't want your naming strategy to add an underscore to the column name or class name, then the strategy that you need to use would look like: spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. The things that you provide in annotations #Table and #Column’s name attribute would remain as it is.
If you don't want to provide annotations and want to manually handle the table name and column names, you should extend the class org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl and override the required methods. If you still use annotations for some of the cases here, remember the overridden methods will apply on the names written in those annotations. spring.jpa.hibernate.naming.physical-strategy=example.CustomStrategy
Related
I have a problem regarding my implementation of a weak entity type. (Note, if that's important: I'm using H2 as my database)
Here is my datamodel:
I'm trying to implement Activity's concatenated primary key using two #ID annotated columns. Here is my activity class as well as its "owner"-class:
#Entity
public class Activity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Id
#ManyToOne
#JoinColumn
private UserGroup group;
...
}
#Entity
public class UserGroup {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
My expected outcome would be, that inside my activity table id is generated by default as identity and group_id is set depending on the corresponding group-join. Basically something like this:
create table activity
(
id bigint generated by default as identity,
begin_date_time timestamp(6),
end_date_time timestamp(6),
name varchar(255) not null,
note varchar(255),
group_id bigint not null,
room_id bigint,
primary key (group_id, id)
);
Instead, spring disregards my #GeneratedValue annotation and sets it to group_id, ignoring my actual activity.id column:
create table activity
(
id bigint not null,
begin_date_time timestamp(6),
end_date_time timestamp(6),
name varchar(255) not null,
note varchar(255),
group_id bigint generated by default as identity,
room_id bigint,
primary key (group_id, id)
);
This is a problem, as I plan on using Rest-Endpoints and Repositories to run CRUD operations using HTTP-requests. Having an ID-counter that increments and gets new IDs for one table only seems unnecessary and dirty.
Can somebody explain to me why this is happening? Can I manually annotate group_id as a manually assigned field as a quick workaround?
Cheers!
What you are looking for is a composite key, which you can create with either #IdClass or with #Embeddable and #EmbeddedId. The catch is, however, that neither of these approaches will work with a #GeneratedId.
If you think about it, there's no need to have a composite key where one of the parts is autogenerated. Just have one Id on your entity that's auto generated, and if you want, create an index across (group_id, id).
I have Hibernate 5.2.10 version and hibernate-jpa-2.1-api with version 1.0.0.Final. I am using MairaDB as database. In persistance.xml, set the property hibernate.ejb.naming_strategy as DefaultComponentSafeNamingStrategy but still I receive the same error:
Repeated column in mapping for entity. I do not want to use #attributeoverrides hibernate and I tried different methodes but still the same error. I want two or more embedded enities.
Thanks
You can't use DefaultComponentSafeNamingStrategy with Hibernate 5, because of it is an implementation of the old NamingStrategy interface from Hibernate 4.
As you probably know, Hibernate 5 uses two new interfaces ImplicitNamingStrategy and PhysicalNamingStrategy.
You can use this implicit naming strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl.
You will need to set hibernate.implicit_naming_strategy property (not hibernate.ejb.naming_strategy).
For these entities
#Embeddable
public class AuthorInfo {
#Column
private String authorInfo;
#OneToOne
private Book bestBook;
}
#Entity
public class Book {
#Id
private Long pid;
#Embedded
private AuthorInfo firstAuthor;
#Embedded
private AuthorInfo secondAuthor;
}
it creates this schema
create table Book (
pid bigint not null,
firstAuthor_authorInfo varchar(255),
secondAuthor_authorInfo varchar(255),
firstAuthor_bestBook_pid bigint,
secondAuthor_bestBook_pid bigint,
primary key (pid)
)
Unit test to check a schema: TwoEmbeddedStrategyTest.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;
I have such hibernate mapping annotation and I need to translate it to xml one.
#Entity
#Table(name = "nodes")
public class DefaultDiagramNode {
.....
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#JoinColumn(name = "node_id", referencedColumnName = "id")
private Set<NodeProperty> properties;
}
Here is my sql table structure:
CREATE TABLE nodes (
id VARCHAR(255) NOT NULL,
logical_id VARCHAR(255) NOT NULL,
graphical_id VARCHAR(50) NOT NULL,
type VARCHAR(50) NOT NULL,
diagram_id BIGINT,
PRIMARY KEY (id),
FOREIGN KEY (diagram_id) REFERENCES diagrams (diagram_id)
);
CREATE TABLE node_properties (
property_id VARCHAR(255) NOT NULL,
name VARCHAR(50) NOT NULL,
value VARCHAR(255) NOT NULL,
type VARCHAR(50) NOT NULL,
node_id VARCHAR(255),
PRIMARY KEY (property_id),
FOREIGN KEY (node_id) REFERENCES nodes (id)
);
How can I do it?
Annotations really are a better choice for a new application. They are easier to read, remove the obtuse relationship between POJO and XML, and they less will result in less lines of code to maintain later. The annotations will also make it far easier to refactor your applications using IDEs such as Eclipse or IntelliJ.
Is there a pressing need to go back to XML? Otherwise, I'd avoid it.
Edit:
Ah, makes sense since you're using Thrift. Have have you tried looking at Swift? You may be able to just add these annotations to your Hibernate entity classes. https://github.com/facebook/swift/
I have an entity with a map. I am using Hibernate on PostgreSQL. The classes in the map are defined by Java and cannot be annotated by me. The class I am modifying was generated from an XML Schema I cannot change.
So I have
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
#Entity public class TestClass {
#XmlTransient
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long pk;
...
#XmlAnyAttribute
#ElementCollection(fetch = FetchType.EAGER)
#Embedded
private final Map<QName, String> otherAttributes = new HashMap<QName, String>();
...
I am using PostGreSQL, and I am getting the following error:
Unsuccessful: create table TestClass_otherAttributes (TestClass_pk int8 not null, count int4 not null, hash int4 not null, offset int4 not null, value varchar(255), localPart varchar(255), namespaceURI varchar(255), prefix varchar(255), primary key (TestClass_pk, localPart, namespaceURI, prefix))
ERROR: syntax error at or near "offset" Position: 160
Clearly this means that the order field in one of the strings (most likely in QName, but it's hard to be certain) is reserved and so the create table is failing.
I have researched this and have found a number of other annotations that affect how the join table it built and named, but nothing that allows me to quote the field names (again, without the ability to annotate QName or String) nor affect the column name that doesn't require annotations in the key or value classes.
So my question is, what is the minimum number of annotations to add so I can persist this map?
offset is a reserved word in PostgreSQL and in the 2008 standard:
http://www.postgresql.org/docs/current/interactive/sql-keywords-appendix.html
If you have access to the SQL, or can control how it is emitted, you could put the column name in quotes (the double-quote character: ["]). A quoted identifier is always taken as an identifier and never collides with reserved words. If you can't cause the column name to be changed, nor quote it, you can't get it to work in PostgreSQL or any SQL-2008 conforming database product.