Hibernate HQL Count and Implicit Join result are different - java

I have Class A with fields
Long id
B activity
And related class B
Long id
String name
Then I have the HQL query:
select a.id, a.activity.name from A a;
Some B fields on class A have null values, so left join gives more results than inner join.
I'm generating automatically the HQL, so I want the select and then the count:
select count(*) from A;
This gives me different results.
Is some way to resolve this, other than adding the explicit left join on the SQL (I'm receiving the HQL, can't change it).

Try execute the count with the same query, this way:
Query query = getEm().createQuery("select a.id, a.activity.name from A a");
int count = query.getResultList().size();
Or if you want to create a native query, configure your persistence.xml to enable log statement. So you can modify the original select to make the count.
Statement logging and statistics
hibernate.show_sql
hibernate.format_sql
hibernate.use_sql_comments
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="show_sql" value="true" />
<property name="format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>

Related

Executing Oracle Stored Procedure with Hibernate

I have been trying to execute an Oracle Stored Procedure using Hibernate. This is not for production - but for a Java source parsing project, that I'm pursuing. To put it in simple terms, I'm not able to return a value from an Oracle Stored Proc.
I have searched and read all relevant links from SO, Hibernate community/documentation(Native SQL chapter) links and tried out the suggestions, but somehow couldn't get them to work. Below are my sources - I'm including only the relevant parts.
My Entity Class. I have reserved the first parameter for a PL/SQL OUT parameter.
Login.java
#NamedNativeQuery(
name = "getLoginDet",
query = "call GET_LOGIN_DET(?,:userId)",
resultClass = Login.class)
#Entity
#Table(name = "T_LOGIN_DET")
public class Login {
Oracle Stored Proc : GET_LOGIN_DET.sql. The first parameter is OUT REFCURSOR as per Hibernate Spec
create or replace PROCEDURE GET_LOGIN_DET(listLogin OUT SYS_REFCURSOR,userId IN VARCHAR2)
AS
BEGIN
OPEN listLogin FOR
SELECT *
FROM T_LOGIN_DET
WHERE USER_ID = userId;
END GET_LOGIN_DET;
My DAO Class : I'm binding only the named parameter, ignoring the first ? in the named Query.
Session session = sessionFactory.openSession();
List results = session.getNamedQuery("getLoginDet").setParameter("userId", u.getUserId()).list();
My Hibernate Config
<bean id="mysessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.cogn.gto.sea.employee.entity.Employee</value>
<value>com.cogn.gto.sea.employee.entity.Department</value>
<value>com.cogn.gto.sea.login.entity.User</value>
<value>com.cogn.gto.sea.login.entity.Login</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
However, I always end up with Hibernate QueryException / Java SQLException
Expected positional parameter count: 1, actual parameters: [] [{call GET_LOGIN_DET(?,:userId)}]
I have tried variations of {? = call GET_LOGIN_DET(:userId)} , call GET_LOGIN_DET(?,:userId) to no avail. My requirement is to call the procedure that I have listed and get the result back in the DAO class. Can someone lead me to what exactly I'm missing here ?
I believe you have incorrectly declared call to stored procedure (curly brackets missing), try this:
#NamedNativeQuery(
name = "getLoginDet",
query = "{call GET_LOGIN_DET(?,:userId)}",
resultClass = Login.class
hints = {#QueryHint(name = "org.hibernate.callable", value = "true")})
#Entity
#Table(name = "T_LOGIN_DET")
public class Login {

Can I generate JPA entities with EAGER fetchType by default?

Im using JPA persistence.xml and generating my entities with the Hibernate code generator. My persistence.xml looks like this:
<persistence-unit name="my_schema">
... classes ...
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://10.12.200.101:3306/my_schema"></property>
<property name="hibernate.default_catalog" value="my_schema" />
<property name="hibernate.connection.username" value="my_user"></property>
<property name="hibernate.connection.password" value="my_pass"></property>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"></property>
<property name="hibernate.connection.nombre" value="my_schema" />
</properties>
</persistence-unit>
All my entities are generated with the FetchType.LAZY by default:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "entity_name")
Is there a way to generate this entities with FetchType.EAGER by default?
All #ManytoOne and #OneToOne relationships are EAGER by default.
The #OneToMany associations are LAZY for a very good reason.
Assuming you have a root entity:
Country, having a one-to-many association states
each State has a one-to-many association cities
each City has a one-to-many association streets
each Street has a one-to-many association HouseNumbers
If you have the default option of fetching all these one-to-many associations eagerly, it could be that selection one Country will end up fetching the whole database.
This is a major performance concern and you should plan your fetching strategy responsively.
If all your one-to-many associations are fetched eagerly, and one parent entity (Parent) has 2 unrelated one-to-many associations (children and jobs) then fetching the parent entity will end up in a Cartesian Product of all the one-to-many associations.
So, in conclusion:
plan your fetch strategy carefully
rely less on the default `EAGER fetching
explicitly use fetch joins in all JPQL or Criteria API queries to extract the right amount of info you need for a certain job

Hibernate query, Hibernate restrictions addition

I have 2 tables 'Stock' and 'stockdaily'
Need to fetch all the
"stock_template" from stock where stock_status=true
and
stock.stock_template is the FK to Stockdaily.stock_template.
Right now I am doing this
I wrote in Stockdaily.hbm.xml
<many-to-one class="StockDTO" column="stock_template" name="templates"/>
In StockdailyDTO.java
private StockDTO templates;
In StockDTO
private Boolean stocktemplate;
In Stock.hbm.xml
<property name="stockStatus" type="java.lang.Boolean">
<column name="stock_Status" />
</property>
but whenever I try to fetch data on the basis of restriction stock_statua=true
criteria = session.createCriteria(stockDailyDTO.class).add( Restrictions.eq("templates.stockStatus", true) );
System gives an exception that
org.hibernate.QueryException: could not resolve property: templates.stockStatus of: StockdailyDTO
Can anyone tell me what else should I do to resolve this issue?

How do I use Hibernate's second level cache with JPA?

I am implementing an Entity Attribute Value based persistence mechanism. All DB access is done via Hibernate.
I have a table that contains paths for nodes, it is extremely simple, just an id, and a path (string) The paths would be small in number, around a few thousand.
The main table has millions of rows, and rather than repeating the paths, I've normalized the paths to their own table. The following is the behaviour I want, when inserting into main table
1) Check if the path exists in paths table (query via entity manager, using path value as parameter)
2) if it does not exist, insert, and get id (persist via entity manager)
3) put id as foreign key value to main table row, and insert this into main table.
This is going to happen thousands of times for a set of domain objects, which correspond to lots of rows in main table and some other tables. So the steps above are repeated using a single transaction like this:
EntityTransaction t = entityManager.getTransaction();
t.begin();
//perform steps given above, check, and then persist etc..
t.commit();
When I perform step 2, it introduces a huge performance drop to the total operation. It is begging for caching, because after a while that table will be at most 10-20k entries with very rare new inserts. I've tried to do this with Hibernate, and lost almost 2 days.
I'm using Hibernate 4.1, with JPA annotations and ECache. I've tried to enable query caching, even using the same query object throughout the inserts, as shown below:
Query call = entityManager.createQuery("select pt from NodePath pt " +
"where pt.path = :pathStr)");
call.setHint("org.hibernate.cacheable", true);
call.setParameter("pathStr", pPath);
List<NodePath> paths = call.getResultList();
if(paths.size() > 1)
throw new Exception("path table should have unique paths");
else if (paths.size() == 1){
NodePath path = paths.get(0);
return path.getId();
}
else {//paths null or has zero size
NodePath newPath = new NodePath();
newPath.setPath(pPath);
entityManager.persist(newPath);
return newPath.getId();
}
The NodePath entity is annotated as follows:
#Entity
#Cacheable
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Table(name = "node_path", schema = "public")
public class NodePath implements java.io.Serializable {
The query cache is being used, as far as I can see from the statistics, but no use for second level cache is reported:
queries executed to database=1
query cache puts=1
query cache hits=689
query cache misses=1
....
second level cache puts=0
second level cache hits=0
second level cache misses=0
entities loaded=1
....
A simple, hand written hashtable as a cache, works as expected, cutting down total time drastically. I guess I'm failing to trigger Hibernate's caching due to nature of my operations.
How do I use hibernate's second level cache with this setup? For the record, this is my persistence xml:
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>...</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.password" value="zyx" />
<property name="hibernate.connection.url" value="jdbc:postgresql://192.168.0.194:5432/testdbforml" />
<property name="hibernate.connection.username" value="postgres"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.search.autoregister_listeners" value="false"/>
<property name="hibernate.jdbc.batch_size" value="200"/>
<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.generate_statistics" value="true"/>
<property name="hibernate.cache.use_structured_entries" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
</properties>
Ok, I found it.
My problem was that, cached query was keeping only Ids of query results in the cache, and it was (probably) going back to db to get the actual values, rather than getting them from the second level cache.
The problem is of course, the query did not put those values to second level cache, since they were not selected by primary id. So the solution is to use a method that will put values to second level cache, and with hibernate 4.1, I've manage to do this with natural id. Here is the function that either inserts or returns the value from cache, just in case it helps anybody else:
private UUID persistPath(String pPath) throws Exception{
org.hibernate.Session session = (Session) entityManager.getDelegate();
NodePath np = (NodePath) session.byNaturalId(NodePath.class).using("path", pPath).load();
if(np != null)
return np.getId();
else {//no such path entry, so let's create one
NodePath newPath = new NodePath();
newPath.setPath(pPath);
entityManager.persist(newPath);
return newPath.getId();
}
}

Good way to generate SQL strings in java?

I'm not looking for a persistence layer like Hibernate, I just want to generate SQL-strings and they should be compatible with PreparedStatement. I've tried libraries such as Squiggle, but it only supports SELECT, I would also like to generate insert and updates. An ideal usage would be something like:
generateInsertOn("myTable").addValue("value1").addValue("value2").generate();
that would generate this string:
"INSERT INTO myTable (value1, value2) VALUES(?, ?)"
I know that there exists questions that are a lot like mine, such as this, but they don't quite ask the same thing as I do.
For arbitrary SQL, use jOOQ. jOOQ currently supports SELECT, INSERT, UPDATE, DELETE, TRUNCATE, and MERGE. You can create SQL like this:
// Since you're not executing the SQL, set connection to null
Connection connection = null;
Factory create = new MySQLFactory(connection);
String sql1 = create.select(A, B, C)
.from(MY_TABLE)
.where(A.equal(5))
.and(B.greaterThan(8))
.getSQL();
String sql2 = create.insertInto(MY_TABLE)
.values(A, 1)
.values(B, 2)
.getSQL();
String sql3 = create.update(MY_TABLE)
.set(A, 1)
.set(B, 2)
.where(C.greaterThan(5))
.getSQL();
The supported syntax is quite rich. You will also find support for clauses such as ON DUPLICATE KEY UPDATE, FOR UPDATE, LOCK IN SHARE MODE, etc.
For more details, see
http://www.jooq.org
(Disclaimer, I work for the company behind jOOQ)
You should definitively take a look at SQLBuilder. It allows simple, yet complete, SQL generation using a very fluent API.
Going out on a limb here, have you considered iBatis? It's a real down to earth query mapping framework (I hesitate to call it an ORM framework somehow). You have to create XML files like this one:
<mapper namespace="org.mybatis.jpetstore.persistence.ProductMapper">
<cache />
<select id="getProduct" parameterType="string" resultType="Product">
SELECT
PRODUCTID,
NAME,
DESCN as description,
CATEGORY as categoryId
FROM PRODUCT
WHERE PRODUCTID = #{productId}
</select>
</mapper>
which wires up a mapper like this one:
public interface ProductMapper {
Product getProduct(String productId);
}
Which allows you to access data from services like this:
#Autowired
private ProductMapper productMapper;
public Product getProduct(String productId) {
return productMapper.getProduct(productId);
}
Which you can wire up with Spring:
<!-- enable autowire -->
<context:annotation-config />
<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven />
<!-- define the SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="org.mybatis.jpetstore.domain" />
</bean>
<!-- scan for mappers and let them be autowired -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.jpetstore.persistence" />
</bean>
See also the full petstore example.
I'm not an uniquivocal fan of iBatis but it might fit your needs in this specific case.

Categories

Resources