Hi I have a confusing error with my Spring-boot-JPA-Hibernate classes.
I used the JPA Dali tools to create the Entity classes from my SQL Schema.
While using them (with Spring-boot-jpa / hibarnate) I have some strange problems with unmatched queries.
Here is one example:
Properties:
hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://localhost:3306/users
spring.datasource.username=root
spring.datasource.password=root
Entity:
#Entity
#Table(name="n_user")
#NamedQuery(name="NUser.findAll", query="SELECT n FROM NUser n")
public class NUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int id;
private String imageUrl1;
private String name_first;
public NCaterer() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getImageUrl1() {
return this.imageUrl1;
}
public void setImageUrl1(String imageUrl1) {
this.imageUrl1 = imageUrl1;
}
public String getName_first() {
return this.name_first;
}
public void setName_first(String name_first) {
this.name_first = name_first;
}
}
Repository:
public interface UserRepo extends CrudRepository<NUser, Long> {
}
But Hibernate creates this query of it:
Hibernate:
/* select
generatedAlias0
from
NUser as generatedAlias0 */ select
nuser0_.id as id1_0_,
nuser0_.image_url1 as image_ur2_0_,
nuser0_.name_first as name_firs3_0_
from
n_user nuser0_
The Problem here is the image_url1 it should be imageurl1 as described in the Entity class. This happens on several points.
Why do Hibernate transform CamelCase getters into camel_case in the query? And how can I config it not to do it?
If you want to specify column name by your own use #Column annotation for your fields.
Example:
#Column(name = "imageUrl1")
private String imageUrl1;
#Column(name = "nameFirst")
private String name_first;
It seems there have been many people experiencing the same problem in different circumstances. Maybe go and have a look at the different naming strategies below:
Naming Strategy One
Naming Strategy Two
Naming Strategy Three
You can however change the configuration of your hibernation. Have a look here for further help with regards to that. Or, go and have a look at this post and see how someone changed it using the above methods.
Related
I have a model class that is mapped to a postgres database using hibernate. My model class is:
CheckRes.java
package com.example.demo.model;
import javax.persistence.Id;
import javax.persistence.*;
#Entity
#Table(name="checkers",schema = "public")
public class CheckRes {
public long getID() {
return ID;
}
public void setID(long ID) {
this.ID = ID;
}
public String getCheck() {
return check;
}
public CheckRes() {
}
public void setCheck(String check) {
this.check = check;
}
#Id
private long ID;
public CheckRes(String check) {
this.check = check;
}
#Column(name="check")
private String check;
}
application.properties
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.hibernate.ddl-auto = update
The following table is already existing in db with create script as:
CREATE TABLE public."checkers"
(
"ID" bigint NOT NULL,
"check" character varying(20),
CONSTRAINT "checkers_pkey" PRIMARY KEY ("ID")
)
TABLESPACE pg_default;
ALTER TABLE public."checkers"
OWNER to postgres;
Later when I am trying to invoke the controller get method from a postman , I am getting the following error.
org.postgresql.util.PSQLException: ERROR: column checkres0_.id does not exist
Position: 8
If the table doesnt exist then hibernate automatically creates a table with '_' and there are no errors. But I dont need the hibernate to create any tables. It just needs to use the existing ones for CRUD operations,is there any other naming convention I am missing?
Generally, this is a good practice to follow java naming conventions. According to that you should rename ID field to id.
And then as was noticed by #User-Upvotedon'tsayThanks and #a_horse_with_no_name you should use #Column with quotes:
#Id
#Column(name="`ID`")
private long id;
Also your getters and setters should follow JavaBean conventions. So, for the above field you should have the following getter and setter:
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
I'm getting the following error:
Could not determine type for: java.util.Set, at table: Ruleset, for columns: [org.hibernate.mapping.Column(ruleset)]
class snippet:
#Entity
public class Ruleset implements java.io.Serializable {
#Id
#OneToOne(targetEntity = RulesetStatus.class)
private Integer id;
private Set<Rule> ruleset = new HashSet<Rule>(0);
public Ruleset() {
}
public Ruleset(Integer ID, Set<Rule> ruleset) {
this.id = ID;
this.ruleset = ruleset;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<Rule> getRuleSet(){
return this.ruleset;
}
public void setRuleset(Set<Rule> ruleset) {
this.ruleset = ruleset;
}
}
I've figured out that annotating ruleset as Transient makes the problem go away, but then ruleset won't be persisted to the DB. How do I tell hibernate about the type of this field?
I'm very new to Hibernate so I'm totally lost here.
__________________________Edit__________________________
The actual relationship should have been #ManyToMany as a rule can be in many rulesets and a ruleset can have many rules.
I added the #ManyToMany annotation to the set, then did not have a corresponding set in the Rule Class to map to. I added the set in the rule class, added the #ManyToMany annotation to that, and no I have no errors.
Does this seem correct?
By default, all fields (or properties) are mapped in JPA. That's why you have to tell the JPA provider what your Set is supposed to map (one-to-many, many-to-many, #ElementCollection, etc.), or map it as #Transient to tell the provider that you don't want the property to be persisted.
I'm building one application using JPA, I want to have a parent entity called "BaseEntity" with the attribute ID and then the rest of the entities extending this entity and then having their own attributes. The field id in the parent class is protected. However when I start the server I'm getting the following error:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: com.fgonzalez.domainmodel.User
Of course if I place the id field in the class User, it is working fine but this is not what I want. The weird thing is if I use xml files for the hibernate mappings instead of JPA, it works fine, but not with JPA. Any idea where can be the problem? Attached the code:
Base Entity:
public class BaseEntity implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
And User entity:
#Entity
#Table(name="users")
public class User extends BaseEntity{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
*
*/
#Column(name="EMAIL",nullable=false,length=50,insertable=true,updatable=true)
private String email;
#Column(name="PASSWORD",nullable=false,length=50,insertable=true,updatable=true)
private String password;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email=email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Thank you in advance!!
You can't do that this way: BaseEntity isn't an #Entity, so #Id shouldn't even be processed.
If Hibernate does process it while using xml, that's probably a non-portable specificity.
You could implement some entity hierarchy, but I wouldn't do it in this case. You can only extend once, and this doesn't look like a real hierarchy: only one root, shared by every class?
You can find more information on entity inheritance here: http://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html
You could use compositions instead of inheritance. In this case, just annotate your User class (which wouldn't be an #Entity) with #Embeddable, and have a field annotated with #EmbeddedId on the using class.
Still, I wouldn't do that: it seems more DRY, but it has no more benefits that replacing String everywhere with something else just to not repeat yourself (which you would then do anyway).
I would just have an #Id Long id; field in every entity, freeing them from hierarchy hell. It looks more boilerplate, but will be much easier in the long term, with no obvious disadvantage.
If you are going implement inheritance in JPA, you are not suppose to do like in java. JPA got its own implementation strategies. Have a look here and choose the one that best suits your need
My application works with 2 databases: 1 SQL Server and 1 PostgreSQL.
The SQL Server is used for the website and had some performance issues in the past, therefore, I separated some analysis data into a different database, where I am adding data constantly and calculate some things all day long.
In most of the cases I use the databases separately, but in one case I would like to join two tables from different databases.
Is there any way I can do this with Hibernate?
To exemplify, I have this two simplified entities: Order and OrderSource.
The Order Table is in the SQL Server and OrderSource is in the PostgreSQL.
They both work fine by themselves, but when I added the OrderSource to the entity Order and Order to the entity OrderSource, it obviously went wrong, because they are trying to access a database that is configured in another SessionFactory.
Order Entity:
#Entity
#Table(name=DomainConstants.TB_ORDER, schema=DomainConstants.DB_SCHEMA)
public class Order {
#Id
#Column(name="cod")
#GeneratedValue
private Long id;
#OneToOne(mappedBy="order", fetch=FetchType.LAZY)
private OrderSource orderSource;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public OrderSource getOrderSource() {
return orderSource;
}
public void setOrderSource(OrderSource orderSource) {
this.orderSource = orderSource;
}
}
OrderSource Entity:
#Entity
#Table(name=DomainConstants.TB_ORDER_SOURCE, schema=DomainConstants.DB_SCHEMA_GOOGLE)
public class OrderSource {
#Id
#Column(name="id")
private long id;
#Column(name="source")
private String source;
#Column(name="medium")
private String medium;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="id")
private Order order;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getMedium() {
return medium;
}
public void setMedium(String medium) {
this.medium = medium;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
One solution I could come up with was to work on my OrderService with my OrderDao and my OrderSourceDao.
This way I removed the mapping from each of the entities and created one Service to get all Orders and iterate over all of them getting the OrderSource.
This is, however, not as fast as I would like and I am not able to group data or order them.
#Component
public class OrderServiceImpl implements OrderService {
private OrderDao orderDao;
private OrderSourceDao orderSourceDao;
#Autowired
public OrderServiceImpl(OrderDao orderDao, OrderSourceDao orderSourceDao) {
this.orderDao = orderDao;
this.orderSourceDao = orderSourceDao;
}
public List<Order> getOrdersWithOrderSource() {
List<Order> orders = this.orderDao.index(); // get all Orders
for(Order order: orders)
order.setOrderSource(this.orderSourceDao.findById(order.id)); // Find OrderSource by Order id
}
}
Has anyone come across something like this? Does anyone have a solution for this join on different databases?
Thanks so much everyone!
Have you considered using an SQL query to join the tables over the DB link and then via ResultSetHandler map it to the entities (if it's just for view purposes) or based on this retrieve set of IDs in the DB where you want to make the change and then select the entities through HQL and ID set so you could store them to your main DB (I am assuming your main DB where you would want to change the data is the web one and not the analytical one)?
I'm using hibernate JPA (without Spring) and it's working well, but I have come across a problem which has stumped me for the last 3 days.
I have written some generic DAO classes and am using them to persist my objects. They all work fine, except for one class of object which is not being persisted. No exceptions are thrown. I've tried debugging inside the hibernate code and found that the reason the entity is not being persisted is that in the org.hibernate.event.def.DefaultFlushListener onFlush() method, source.getPersistenceContext().getEntityEntries().size() == 0 so no flushing is performed. But I can't work out why that would be the case.
The classes in question look like this:
#Entity
#Table(name="er_batch_runs")
public class BatchRun implements Serializable, Comparable<BatchRun>, BatchBean {
private Long runId;
private String hostname;
.... more field here
#Override
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="runseq")
#SequenceGenerator(name="runseq", sequenceName="er_batch_runs_seq", allocationSize=1 /*, initialValue = 10*/)
#Column(name="batch_run_id")
public Long getId() {
return runId;
}
public void setId(long runId) {
this.runId = runId;
}
#Column(name="hostname")
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
pretty straightforward hibernate JPA stuff.
Here's another class:
#Entity
#Table(name="er_batch_txns")
public class BatchTxn implements Serializable, Comparable<BatchTxn>, BatchBean {
private long id;
.......... more fields
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="batchtxnseq")
#SequenceGenerator(name="batchtxnseq", sequenceName="ER_BATCH_TXNS_SEQ", allocationSize=1/*00, initialValue = 10*/)
#Override
#Id
#Column(name="BATCH_TXN_ID")
public Long getId() {
return id;
}
the BatchBean interface is what allows me to use generic DAOs like this:
public Long create(BatchBean newInstance) {
getOpenEntityManager().persist(newInstance);
logger.debug("hopefully created {} with id {}",newInstance.getTypeName(),newInstance.getId());
return newInstance.getId();
}
Transactions are being handled manually. I've set the flush type to COMMIT (ie flush on commit) and when I've completed the persist, I do a commit. After the persist, then BatchTxn object has been assigned a primary key from the sequence. When I debug hibernate I can see that getPersistenceContext().getEntityEntries() returns an empty Map.
so the question is why the BatchTxn is not being persisted by the commit, when the BatchRuns, and 5 other classes which implement BatchBean, are?
I'm using hibernate 3.6.0 Final
The only thing I saw that is suspected in your code is this in the BatchTxn class:
private long id;
This will be set automatically to zero. Maybe you should use Long (with a capital letter)?