Following is my DTO object of customer class. When i make some get query on hibernate i receive 1064 error
#Entity
#Table(name="customer")
public class Customer implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private int id;
#Column(name="code")
private String code;
#Column(name="address")
private String address;
#Column(name="phone1")
private String phone1;
#Column(name="phone2")
private String phone2;
#Column(name="credit_limit")
private BigDecimal creditLimit;
#Column(name="current_credit")
private BigDecimal currentCredit;
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn(name="customer_id")
private Set<Order> orders;}
then i call following method
public List<Order> allOrders(){
return orderDao.findAll();
}
this is the error i receive.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order orders0_ where orders0_.customer_id=5' at line 1
Hibernate:
select
customer0_.id as id1_0_,
customer0_.address as address2_0_,
customer0_.code as code3_0_,
customer0_.credit_limit as credit_l4_0_,
customer0_.current_credit as current_5_0_,
customer0_.phone1 as phone6_0_,
customer0_.phone2 as phone7_0_
from
customer customer0_
Hibernate:
select
orders0_.customer_id as customer2_0_0_,
orders0_.id as id1_1_0_,
orders0_.id as id1_1_1_,
orders0_.customer_id as customer2_1_1_
from
order orders0_ where
orders0_.customer_id=?
Can you please tell what i'm doing wrong here
The problem is your Order entity: order is a reserved word in sql. Best is to change the table name to something else, e.g. #Table(name = "orders") - with an s.
Alternatively, see this answer:
If you are using Hibernate 3.5+, try
hibernate.globally_quoted_identifiers=true to quote all database
identifiers (this is something they added for JPA 2.0, see the secion
2.13 Naming of Database Objects of the spec for the JPA way to activate this if you are using JPA).
Related
I have a very primitive Entity:
#Entity
#Table(name = "person")
public class Person {
#Id
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "address")
private String address;
}
I use a simple JpaRepository<Person, Integer> with no overriding methos. Whenever I invoke repository.findAll()method I get the following log:
org.hibernate.SQL :
select
person0_.id as id1_2_,
person0_.address as address2_2_,
person0_.name as name3_2_
from
person person0_
Hibernate:
select
person0_.id as id1_2_,
person0_.address as address2_2_,
person0_.name as name3_2_
from
person person0_
The same result I get invoking repository.getOne(). Repository while trying to get a very simple data uses two identical queries one after another with seemingly no particular reason. Is this just how it visualise or is it actually making two queries instead of one? Why is that?
I'm trying to make some field readOnly -> insert and update aka save() should not send that field to DB but the field should be populated with select.
#ReadOnlyProperty from org.springframework.data.annotation.ReadOnlyProperty does not do the trick.
versions: spring-boot: 2.2.0.RC1, spring-data-jdbc: 1.1.0.RELEASE, spring-data-commons: 2.2.0.RELEASE
db: MSSQL
spring-data-jdbc readOnly
Should it work and is there any other way to do it?
NOTE: please don't mix spring-data-jdbc with spring-data-jpa
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
public class Organization {
#Id
private Long id;
private String name;
#Column("readOnlyProperty")
#ReadOnlyProperty
private String readOnlyProperty;
#ReadOnlyProperty
#MappedCollection
private Set<Employee> employees;
}
import org.springframework.data.annotation.Id;
public class Employee {
#Id
private Long id;
private String name;
}
#Test
public void insert() {
// insert should not set readOnlyProperty
Organization organization = new Organization("org1", "readOnly");
Employee employee = new Employee("emp1");
Set<Employee> employess = new HashSet<>();
employess.add(employee);
organization.setEmployees(employess);
organizationRepository.save(organization);
}
LOG:
Executing prepared SQL statement [INSERT INTO organization (name, readOnlyProperty) VALUES (?, ?)]
Executing prepared SQL statement [INSERT INTO employee (name, organization) VALUES (?, ?)]
This is a bug.
I created DATAJDBC-431 for it and it will probably fixed in the next service release.
I didn't test, but according to this
The Column annotation and XML element defines insertable and updatable options. These allow for this column, or foreign key field to be omitted from the SQL INSERT or UPDATE statement. These can be used if constraints on the table prevent insert or update operations. They can also be used if multiple attributes map to the same database column, such as with a foreign key field through a ManyToOne and Id or Basic mapping. Setting both insertable and updatable to false, effectively mark the attribute as read-only.
#Column(name="COLUMN_NAME",updatable=false, insertable=false)
private String fieldName;
should make the field read-only.
We have a deleted column on our table, is it possible to check that every time this table is queried the query has a condition for this column?
Some googling with better keywords (soft-delete) it seems I could do this with #When annotation. not exactly what I was looking but seems close enough.
You can check out #Where annotation.
org.hibernate.annotations.Where
Example:
If there's an Account Entity
#Entity(name = "Account")
#Where( clause = "active = true" )
public static class Account {
#Id
private Long id;
#ManyToOne
private Client client;
#Column(name = "account_type")
#Enumerated(EnumType.STRING)
private AccountType type;
private Double amount;
private Double rate;
private boolean active;
//Getters and setters omitted for brevity
}
and if the following code is used for fetching the accounts.
List<Account> accounts = entityManager.createQuery(
"select a from Account a", Account.class)
.getResultList();
then the following SQL will be generated
SELECT
a.id as id1_0_,
a.active as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE ( a.active = true )
Hibernate ORM 5.2.18.Final User Guide
I am working on a Hibernate issue, which involves 2 separate Entity beans defined separately in their own classes:
Store
StoreServer
Note that a Store will have more than one StoreServer - hence the use of the #OneToMany annotation. Please see the code snippets as follows:
Store:
#Entity
#Table(name="Store")
public class Store implements Serializable {
/**
* Serializable class - generated UID
*/
private static final long serialVersionUID = 5644190852867691168L;
#Id
#Column(name="STORE_NO", nullable=false)
private int storeNumber;
#Column(name="STORE_NAME", nullable=false)
private String storeName;
#Column(name="STORE_PHONE", nullable=false)
private String storePhone;
//other Store fields...
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name="STORE_NO", insertable=false, updatable=false)
private List<StoreServer> storeServers = new ArrayList<StoreServer>();
//getters and setters
StoreServer:
#Entity
#Table(name="Store_Server")
public class StoreServer implements Serializable {
/**
* Serializable class - generated UID
*/
private static final long serialVersionUID = -5410564578856243437L;
#Id
private StoreServerPK storeServerPK;
#Column(name="IP_ADDRESS", nullable=true)
private String ipAddress;
//other StoreServer fields...getters and setters
Since StoreServer has a composite Primary Key, here is StoreServerPK:
#Embeddable
public class StoreServerPK implements Serializable {
/**
* Serializable class - generated UID
*/
private static final long serialVersionUID = -1401889029390423604L;
#Column(name="STORE_NO", nullable=false)
protected int storeNumber;
#Column(name="SERVER_NO", nullable=false)
protected String serverNumber;
//getters and setters
At present, I am getting the correct results, but the performance is unacceptably SLOW. I have switched on logging in Hibernate and I can see that a separate SELECT query is being run for each Store Entity in order to obtain the associated StoreServer records.
Currently, in the logs, I see a single SELECT statement to obtain the Store records (more than 200 results returned). Then for each store, a new SELECT statement to get the StoreServer records. My question is...Why is Hibernate not doing a join (running one query)?
Please could I get some help on how to tell Hibernate to run a single query, using a JOIN?
Thank you
It is called N+1 problem
The solution actually depends on how do you make your query - in case if you are using Criteria API you should use Root.fetch method:
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Store> cq = qb.createQuery(Store.class);
Root<Store> root = cq.from(Store.class);
root.fetch(App_.storeServers, JoinType.LEFT);
cq.select(root);
return em.createQuery(cq).getResultList();
If you are using HQL you should use fetch keyword:
select distinct st from Store st left join fetch st.storeServers
It might be a good idea to validate the number of queries generated by Hibernate in your unit tests using in-memory database like H2 and JDBC Sniffer
I'm developing a webapp using Spring MVC and Hibernate. Thing is, that I need to show all my customer's clients, and each client has another entity associated ("Cobrador", I don't know the english translation here, sorry), I'm using JQgrid for such goal. When I execute the grid, I see in the log:
Hibernate: select cliente0_.id as id1_0_, cliente0_.activo as activo2_0_, cliente0_.apellido as apellido3_0_, cliente0_.cobrador as cobrador8_0_, cliente0_.dni as dni4_0_, cliente0_.email as email5_0_, cliente0_.nombre as nombre6_0_, cliente0_.telefono as telefono7_0_ from clientes cliente0_ where cliente0_.activo=1
Hibernate: select cobrador0_.id as id1_1_0_, cobrador0_.activo as activo2_1_0_, cobrador0_.apellido as apellido3_1_0_, cobrador0_.dni as dni4_1_0_, cobrador0_.email as email5_1_0_, cobrador0_.nombre as nombre6_1_0_, cobrador0_.telefono as telefono7_1_0_ from cobradores cobrador0_ where cobrador0_.id=?
Hibernate: select cobrador0_.id as id1_1_0_, cobrador0_.activo as activo2_1_0_, cobrador0_.apellido as apellido3_1_0_, cobrador0_.dni as dni4_1_0_, cobrador0_.email as email5_1_0_, cobrador0_.nombre as nombre6_1_0_, cobrador0_.telefono as telefono7_1_0_ from cobradores cobrador0_ where cobrador0_.id=?
Hibernate: select cobrador0_.id as id1_1_0_, cobrador0_.activo as activo2_1_0_, cobrador0_.apellido as apellido3_1_0_, cobrador0_.dni as dni4_1_0_, cobrador0_.email as email5_1_0_, cobrador0_.nombre as nombre6_1_0_, cobrador0_.telefono as telefono7_1_0_ from cobradores cobrador0_ where cobrador0_.id=?
Basically getting the clients, and then, for each client go gets the associated "cobrador". My Client entity is configured as follow:
#Entity
#Table(name="clientes")
public class Cliente {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String apellido;
private String nombre;
private int dni;
private String telefono;
private String email;
private boolean activo;
#ManyToOne
#JoinColumn(name="cobrador")
#Fetch(FetchMode.JOIN)
private Cobrador cobrador;
//Contructors, getters and setters
}
BTW: The final hibernate execution is:
#Override
#Transactional
public List<T> getAllFiltering(String filter) {
Query q = sessionFactory.getCurrentSession().createQuery("from " + type.getSimpleName() + " " + filter);
return q.list();
}
Where is and filter is " where activo=true".
Is there anyway to configure this relationship in order to execute only 1 query when loading the grid?
Thanks in advance!
I know it is not very convenient but Hibernate will not use the fetch strategy if you are using an HQL query (I.E using the createQuery method). If you want to make it work, you must use the Criteria API or specify the join in the HQL query.
In your case the query might be something like this :
from Cliente c left join fetch c.cobrador
From the Hibernate documentation :
The fetch strategy defined in the mapping document affects:
retrieval via get() or load()
retrieval that happens implicitly when an association is navigated
Criteria queries
HQL queries if subselect fetching is used
As you can see, the fetch strategy defined doesn't affect HQL queries
if JOIN is the fetchMode.