Java HibernateCriteria setFetch not Working - java

i have a Criteria like this
final Criteria criteria = session.createCriteria(Computer.class)
final Criteria studentCriteria = criteria.createCriteria("student","s");
final Criteria schoolCriteria = studentCriteria.createCriteria("school");
everything works OK. but in SchoolCriteria i need the Address which is a property of the School entity
my question is why this is not working
schoolCriteria.setFetchMode("address",FetchMode.JOIN);
i could not see the JOIN in the SQL statement
i just thought that if i am already in the schoolCriteria i could just get the address..
but this is working
criteria.setFetchMode("student",FetchMode.JOIN);criteria.setFetchMode("student.school",FetchMode.JOIN);criteria.setFetchMode("student.school.address",FetchMode.JOIN);
why this.
i am using Hibernate 4.1.5
thanks a lot.

Because you cannot directly fetch child object without fetching parent. when you are trying to do schoolCriteria.setFetchMode("address",FetchMode.JOIN); means you want address object (which is a property of the School entity) after even session get closed but school object is loaded so how can you set address object into student.
You have to do like JamesB given, Read More # Spring Roo doesn't add FetchType.LAZY for fields in .aj files, Should I do it manually?

I think you need to chain the joins together like this:
session.createCriteria(Computer.class)
.setFetchMode("student", FetchMode.JOIN)
.setFetchMode("school", FetchMode.JOIN)
.setFetchMode("address", FetchMode.JOIN)

Related

Hibernate is making extra SQL statement with #ManyToOne and #Lazy fetching object

I would like someone to explain me why Hibernate is making one extra SQL statement in my straight forward case. Basically i have this object:
#Entity
class ConfigurationTechLog (
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long?,
val configurationId: Long,
val type: String,
val value: String?
) {
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "configurationId", insertable = false, updatable = false)
val configuration: Configuration? = null
}
So as you can see, nothing special there. And when i execute this query :
#Query(value = "SELECT c FROM ConfigurationTechLog c where c.id = 10")
fun findById10() : Set<ConfigurationTechLog>
In my console i see this:
Hibernate:
/* SELECT
c
FROM
ConfigurationTechLog c
where
c.id = 10 */ select
configurat0_.id as id1_2_,
configurat0_.configuration_id as configur2_2_,
configurat0_.type as type3_2_,
configurat0_.value as value4_2_
from
configuration_tech_log configurat0_
where
configurat0_.id=10
Hibernate:
select
configurat0_.id as id1_0_0_,
configurat0_.branch_code as branch_c2_0_0_,
configurat0_.country as country3_0_0_,
configurat0_.merchant_name as merchant4_0_0_,
configurat0_.merchant_number as merchant5_0_0_,
configurat0_.org as org6_0_0_,
configurat0_.outlet_id as outlet_i7_0_0_,
configurat0_.platform_merchant_account_name as platform8_0_0_,
configurat0_.store_type as store_ty9_0_0_,
configurat0_.terminal_count as termina10_0_0_
from
configuration configurat0_
where
configurat0_.id=?
Can someone please explain me, what is happening here ? From where this second query is coming from ?
I assume you are using Kotlin data class. The kotlin data class would generate toString, hashCode and equals methods utilizing all the member fields. So if you are using the returned values in your code in a way that results in calling of any of these method may cause this issue.
BTW, using Kotlin data claases is against the basic requirements for JPA Entity as data classes are final classes having final members.
In order to make an association lazy, Hibernate has to create a proxy instance instead of using the real object, i.e. it needs to create an instance of dynamically generated subclass of the association class.
Since in Kotlin all classes are final by default, Hibernate cannot subclass it so it has to create the real object and initialize the association right away. In order to verify this, try declaring the Configuration class as open.
To solve this without the need to explicitly declare all entities open, it is easier to do it via the kotlin-allopen compiler plugin.
This Link can be useful for understand what kind (common) problem is that N + 1 Problem
Let me give you an example:
I have three Courses and each of them have Students related.
I would like to perform a "SELECT * FROM Courses". This is the first query that i want (+ 1) but Hibernate in background, in order to get details about Students for each Course that select * given to us, will execute three more queries, one for each course (N, there are three Course coming from select *). In the end i will see 4 queries into Hibernate Logs
Considering the example before, probably this is what happen in your case: You execute the first query that you want, getting Configuration Id = 10 but after, Hibernate, will take the entity related to this Configuration, then a new query is executed to get this related entity.
This problem should be related in specific to Relationships (of course) and LAZY Fetch. This is not a problem that you have caused but is an Hibernate Performance Issue with LAZY Fetch, consider it a sort of bug or a default behaviour
To solve this kind of problem, i don't know if will be in your case but ... i know three ways:
EAGER Fetch Type (but not the most good option)
Query with JOIN FETCH between Courses and Students
Creating EntityGraph Object that rappresent the Course and SubGraph that rappresent Students and is added to EntityGraph
Looking at your question, it seems like an expected behavior.
Since you've set up configuration to fetch lazily with #ManyToOne(fetch = FetchType.LAZY), the first sql just queries the other variables. When you try to access the configuration object, hibernate queries the db again. That's what lazy fetching is. If you'd like Hibernate to use joins and fetch all values at once, try setting #ManyToOne(fetch = FetchType.EAGER).

Hibernate second level cache for data transfer object (DTO) projection

As I have read in many articles (e.g. here) - to enable Hibernate's second level cache for given entity we need to set cache concurrency strategy on entity via #org.hibernate.annotations.Cache annotation.
#Entity
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Person {
Besides I also use query-level cache (using query.setCacheable(true)) on some queries that fetches this entity and it works well.
My question relates to custom queries that uses DTO projection, so for the queries like this:
Query query = session.createQuery("SELECT new PersonDto(person.id, person.name) FROM Person person WHERE person.name = :name");
query.setParameter("name", name);
query.setCacheable(true);
query.uniqueResult();
Do I need to set #Cache annotation also for PersonDto? I have tried to run the query without the annotation and the DTO was successfully cached.
Could you explain why do we need the annotation for entity objects only and other non-entity objects does not require that?
Thanks.
I'm not 100% on this, but you are manually setting cacheable to true for the query.
The annotation on Person is the equivalent for an entity.
I wouldn't think of it as PersonDTO being cached in this instance. If you were to write another query saying select new PersonDTO(person.id, person.name) from Person person where person.id = 10, I don't think it will look into your cache to see if a PersonDTO with id == 10 exists; whereas, the Entitys cache would because it understands they are the same thing.
I would think of it as the query itself is being cached (meaning if ran again before TTL then cached results would occur). It's caching the fact that you ran this query with a certain name parameter, not that a PersonDTO with that name exists in the cache. Does that make sense?

Error getting BeanDescriptor for path

I tried to fetch some data from a db using Ebean ORM. I have 3 tables named deal and deal_company_branch and company_branch. deal_company_branchis the associate entity. I wrote a query to fetch data,
select d.* from deal d, deal_company_branch dcb where d.deal_id=dcb.dealId and dcb.branchId=3
And then I tried to do the same thing using Ebean ORM like following,
DealDAO.find.fetch("deal").fetch("deal_company_branch").where()
.and(Expr.eq("deal.deal_id", "deal_company_branch.dealId")
, Expr.eq("deal_company_branch.branchId", branchId)).findList();
When I'm executing this I'm getting,
ERROR:Error while retrieving categories:Error getting BeanDescriptor for path deal from com.de.models.Deal
How may I fix this?
So:
fetch("deal_company_branch") ... that looks like a table name when it should instead be a property name and it is optional so you are probably best to leave it out unless you truely want to fetch that data.
.and(Expr.eq("deal.deal_id", "deal_company_branch.dealId") ... you should leave this out entirely
Expr.eq("deal_company_branch.branchId", branchId)).findList(); ... again that looks like a table.column reference rather than the logical property path.
This almost looks like a ManyToMany relationship but you don't include you model. In most cases for ORM queries you should include your model objects so that people can understand better what you are trying to do.
It looks like you should just do:
DealDAO.find.where().eq("companies.branch.id", branchId).findList();
This assumes the Deal entity has a #ManyToMany to "companies" which has a #ManyToOne to "branch" which has an #Id id property.
Ebean will understand from the property paths ("companies.branch.id") what joins it needs to make to support the where clause (and order by clause and fetching).

utilizing JPA Named Queries

When I create an Entity class from a database in NetBeans, it gives me the option to create Named Queries from persistent fields. Accordingly, I see these named queries listed at the top of my Entity class.
What exactly are these queries, and how can I utilize/"call" them?
I'm aware this question is more general than is preferred on SO, so I'm happy to accept a link to a tutorial that answers these questions, but I've been unable to find one myself.
See
JPA Named Queries
If you have:
#NamedQuery(name="Country.findAll", query="SELECT c FROM Country c")
public class Country {
...
}
Use with:
TypedQuery<Country> query = em.createNamedQuery("Country.findAll",Country.class);
List<Country> results = query.getResultList();
See also:
Annotation Type NamedQuery
Tutorial: Build a Web Application (JSF) Using JPA

Update an entity obtained from Select in HQL

say I have obtained a list of class objects from a SELECT statement like
List<MyClass> something = em.createQuery("SELECT m FROM MyClass m").getResultList();
and I called a few setters
for (MyClass thing : something)
thing.setName("a name");
What is the syntax to update these class objects back to the database?
Do I write something like UPDATE MyClass m SET m = :newObject . setParameter("newObject", thing);
This is purely about the update syntax, although I know the manager is able to pickup the changes and write those back to the database for me.
Thanks
are you using traditional hibernate or hibernate JPA implementation?
with traditional hibernate, yourSession.saveOrUpdate(thing) should work
if your code is running with JPA hibernate implementation, use em.merge(thing);

Categories