I would like to know if i can convert this criteria into a detached criteria. I am not understanding detached criteria correctly. can some one help.
Criteria crit = sessionC.createCriteria(OP_DOCTOR_VISIT.class, "OPDV1");
crit.createAlias("OPDV1.OP_VISIT", "OPDV2", JoinType.LEFT_OUTER_JOIN, Restrictions.and(Restrictions.eq("OPDV2.FORM", "NEW"), Restrictions.ge("OPDV2.USER_DATETIME", fromdate), Restrictions.le("OPDV2.USER_DATETIME", todate)));
crit.add(Restrictions.ge("OPDV1.USER_DATETIME", fromdate));
crit.add(Restrictions.le("OPDV1.USER_DATETIME", todate));
ProjectionList p1 = Projections.projectionList();
p1.add(Projections.alias(Projections.count("OPDV1.OP_VISIT_ID"), "TOTAL"));
p1.add(Projections.count("OPDV2.FORM"));
p1.add(Projections.alias(Projections.sqlGroupProjection("date(this_.USER_DATETIME) as createdDate", "createdDate", new String[]{"createdDate"}, new Type[]{StandardBasicTypes.DATE}), "DAT"));
crit.setProjection(p1);
Is it possible to rewrite the above so that I could avoid using "#OneToMany" in my POJO given below.
POJO
#Entity
#Table(name = "OP_DOCTOR_VISIT")
#SQLDelete(sql = "UPDATE OP_DOCTOR_VISIT SET DELETED = 'DELETED' WHERE OP_VISIT_ID = ? and VERSION_UPDATES = ?")
#Where(clause = "DELETED <> 'DELETED'")
public class OP_DOCTOR_VISIT implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "OP_VISIT_ID")
private Long OP_VISIT_ID;
#OneToMany(mappedBy = "OP_VISIT_ID", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#LazyCollection(LazyCollectionOption.EXTRA)
#Fetch(FetchMode.SELECT)
private List<OP_DOCTOR_VISIT> OP_VISIT;
public Long getOP_VISIT_ID() {
return OP_VISIT_ID;
}
public void setOP_VISIT_ID(Long OP_VISIT_ID) {
this.OP_VISIT_ID = OP_VISIT_ID;
}
public List<OP_DOCTOR_VISIT> getOP_VISIT() {
return OP_VISIT;
}
public void setOP_VISIT(List<OP_DOCTOR_VISIT> OP_VISIT) {
this.OP_VISIT = OP_VISIT;
}
}
Only the first line where you create your criteria object.
DetachedCriteria allows you to create a query without session. So you do not require session while builiding your query. DetachedCriteria is same as a Criteria except you can create your queries without session.
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(OP_DOCTOR_VISIT.class);
Finally when you have a session object is available you may execute your query
`criteria .getExecutableCriteria(session).
DetachedCriteria crit = DetachedCriteria.forClass(OP_DOCTOR_VISIT.class, "OPDV1");
The detached criteria allows you to create the query without Session. Then you can execute the search in an arbitrary session.
In fact you should think carefully when use detached criterias using another, or a new, session (no cache, and creation of the session).
They are most useful for make some join conditions, subselects, and to query outside the current session.
Another common use is for code reuse.
If you are using Spring and choose to use HibernateTemplate, it doesn't provide createCriteria() method.
You will find only **DetachedCriteria.
Related
Recently I've encountered problems using Criteria API. It is my very first contact with it. Here is part of my OfficeEntity.
#Entity
#Table(name = "office")
public class OfficeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column (name = "office_id")
private Long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="office_id", referencedColumnName = "office_id")
private List<WorkerEntity> workers = new ArrayList<>();
GOAL - GET LIST OF WORKERS ENTITIES FROM SPECIFIC OFFICE ENTITY.
By now I've figured out how to achieve the goal by this:
#Override
public List<WorkerEntity> getWorkersByOffice(long officeId) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<OfficeEntity> query = cb.createQuery(OfficeEntity.class);
Root<OfficeEntity> office = query.from(OfficeEntity.class);
query.select(office).where(cb.equal(office.get("id"),officeId));
TypedQuery<OfficeEntity> typedQuery = entityManager.createQuery(query);
OfficeEntity foundOffice = typedQuery.getSingleResult();
return foundOffice.getWorkers();
}
And it works fine but I think I rely too much on Java List interface methods instead of Criteria API. Can I get this list of WorkerEntity (field "workers" in OfficeEntity) just by creating proper query in Criteria? If then, can any advise or proper solution be delivered?
Best regards,
Newbie to Hibernate & Criteria.
I am assuming there is two way binding between Office and Worked entities. If not create parent entity in Worked using #ManyToOne annotation. Then the below code should work
#Override
public List<WorkerEntity> getWorkersByOffice(long officeId) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<WorkerEntity> query = cb.createQuery(WorkerEntity.class);
Root<WorkerEntity> worker= query.from(WorkerEntity.class);
OfficeEntity office = new OfficeEntity();
office.setId(officeId);
query.select(worker).where(cb.equal(worker.get("office"),office));
TypedQuery<OfficeEntity> typedQuery = entityManager.createQuery(query);
List<WorkerEntity> workerList= typedQuery.getResultList();
return workerList;
}
I use Hibernate 5.2.5 (also use kotlin and spring 4.3.5 if that matters) and I want some of the fields of my class to be loaded lazily. But the issue is that all fields are loaded immediately, I don't have any special Hibernate settings neither use Hibernate.initialize().
#Entity(name = "task")
#Table(name = "tasks")
#NamedQueries(
NamedQuery(name = "task.findById", query = "SELECT t FROM task AS t WHERE t.id = :id")
)
class Task {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Int? = null
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "author_id", nullable = false)
lateinit var author: User
#OneToOne(fetch = FetchType.LAZY, mappedBy = "task")
var edit: TaskEdit? = null
}
This is how I query
TaskRepoImpl:
override fun findById(id: Int): Task? {
val task = getCurrentSession().createNamedQuery("task.findById", Task::class.java)
.setParameter("id", id)
.uniqueResult()
return task
}
TaskService:
#Transactional
fun find(id: Int): Task? {
return taskRepo.findById(id)
}
And the output:
Hibernate: select task0_.id as id1_1_, task0_.author_id as author_i3_1_ from tasks task0_ where task0_.id=?
Hibernate: select user0_.id as id1_3_0_, user0_.enabled as enabled2_3_0_, user0_.name as name3_3_0_, user0_.password as password4_3_0_ from users user0_ where user0_.id=?
Hibernate: select taskedit0_.id as id1_0_0_, taskedit0_.task_id as task_id3_0_0_, taskedit0_.text as text2_0_0_ from task_edits taskedit0_ where taskedit0_.task_id=?
Please advice what's wrong with my code and how to make Hibernate load properties lazily? Thank you!
Hibernate cannot proxy your own object.
There are at least three well known solutions for this problem:
The simplest one is to fake one-to-many relationship. This will work because lazy loading of collection is much easier then lazy loading of single nullable property but generally this solution is very inconvenient if you use complex JPQL/HQL queries.
The other one is to use build time bytecode instrumentation. For more details please read Hibernate documentation: 19.1.7. Using lazy property fetching. Remember that in this case you have to add #LazyToOne(LazyToOneOption.NO_PROXY) annotation to one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough.
The last solution is to use runtime bytecode instrumentation but it will work only for those who use Hibernate as JPA provider in full-blown JEE environment (in such case setting "hibernate.ejb.use_class_enhancer" to true should do the trick: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this might be hard to achieve on some older application servers). In this case #LazyToOne(LazyToOneOption.NO_PROXY) annotation is also required.
#Entity
public class Animal implements FieldHandled {
private Person owner;
private FieldHandler fieldHandler;
#OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal")
#LazyToOne(LazyToOneOption.NO_PROXY)
public Person getOwner() {
if (fieldHandler != null) {
return (Person) fieldHandler.readObject(this, "owner", owner);
}
return owner;
}
public void setOwner(Person owner) {
if (fieldHandler != null) {
this.owner = fieldHandler.writeObject(this, "owner", this.owner, owner);
return;
}
this.owner = owner;
}
public FieldHandler getFieldHandler() {
return fieldHandler;
}
public void setFieldHandler(FieldHandler fieldHandler) {
this.fieldHandler = fieldHandler;
}
}
Can you try this:
http://justonjava.blogspot.in/2010/09/lazy-one-to-one-and-one-to-many.html
reference:
Why Lazy loading not working in one to one association?
I want to execute a query like this:
SELECT Table1.COL1,
Table1.COL2,
(SELECT SUM(Table2.COL3)
FROM Table2
WHERE Table2.UID = Table1.UID) SUMOF
FROM Table1;
How can I do it?
I usually create a Criteria add ProjectionList to it, to fill COL1 and COL2 only.
I have created a DetachedCriteria to calculate the sum...
Now, how to attach this detached criteria to the main one? My intuition says - it's some sort of Projection which needs to be added to the list, but I don't see how. Also, not sure how WHERE Table2.COL4 = Table1.COL5 of detached criteria will work.
Also, I'm sure this query might be written in different way, for example with join statement. It's still interesting if there's a way to run it like this.
DetachedCriteria and main Criteria
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Table2.class, "table2");
detachedCriteria
.setProjection(
Projections.projectionList()
.add(Projections.sum("table2.col3"), "sumCol3")
)
.add(Restrictions.eq("table2.uid", "table1.uid"))
;
Criteria criteria = session.createCriteria(Table1.class, "Table1");
criteria
.setProjection(
Projections.projectionList()
.add(Projections.property("Table1.col1"), "col1")
.add(Projections.property("Table1.col2"), "col2")
)
;
Entities (very short version)
#Entity
#Table(name = "Table1")
public class Table1 {
#Id
#Column(name = "uid")
public String getUid();
#Column(name = "col1")
public String getCol1();
#Column(name = "col2")
public String getCol2();
#Column(name = "col3")
public String getCol3();
#Column(name = "col4")
public String getCol4();
#Column(name = "col5")
public String getCol5();
}
#Entity
#Table(name = "Table2")
public class Table2 {
#Id
#Column(name = "uid")
public String getUid();
#Column(name = "col3")
public BigDecimal getCol3();
#Column(name = "col4")
public String getCol4();
#Column(name = "col5")
public String getCol5();
}
For a correlated subquery (like the one you presented above), you can use #Formula which can take an arbitrary SQL query. Then, you'll need to fetch the entity and the subquery will be executed.
However, a native SQL is more elegant if you only need this query for a single business requirement.
As for derived table queries (e.g. select from select), neither JPA nor Hibernate support derived table queries for a very good reason.
Entity queries (JPQL pr Criteria) are meant to fetch entities that you plan to modify.
For a derived table projection, native SQL is the way to go. Otherwise, why do you think EntityManager offers a createNativeQuery method?
I've encounterd weird behaviour of JPA (provider: EclipseLink) using order by functionality. I have TransactionData class, which has reference to CustomerData class:
#Entity
public class TransactionData {
//...
#ManyToOne
#JoinColumn(name = "CUSTOMER_ID")
private CustomerData customer;
//...
}
#Entity
public class CustomerData {
//...
#Column(name = "LAST_NAME")
private String lastName;
//...
}
In my project, there are some specific cases, where there are transactions, which are not assigned to any customer (called non-customer transactions).
I try to get list of all registered transactions (both cusotmer transactions and non-customer transactions) and sort them by customer's last name. To acheive this I've written following Criteria Api
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<TransactionData> criteriaQuery = criteriaBuilder.createQuery(TransactionData.class);
Root<TransactionData> from = criteriaQuery.from(TransactionData.class);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("customer").get("lastName"));
TypedQuery<TransactionData> query = entityManager.createQuery(criteriaQuery);
return query.getResultList();
I think I should get list of all transactions, of course, with those, where customer field is set to NULL value. But JPA behaviour is different, because it cut out all transactions, where reference to customer is empty.
from.get("customer").get("lastName") will do implicitly an INNER JOIN. If some transactions have no customer assigned then what you need is a LEFT JOIN:
Join<TransactionData , CustomerData> customer = from.join("customer", JoinType.LEFT);
criteriaQuery.orderBy(criteriaBuilder.asc(customer.get("lastName"));
Given the following entity one-to-many model:
One Repository can be linked to many AuditRecords.
Many AuditRecords can all link to the same Repository
#Entity
class AuditRecordEntity {
private AuditRepositoryEntity auditRepository;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = AUDIT_REPOSITORY_DB_COLUMN_NAME, nullable = false, updatable = false)
public AuditRepositoryEntity getAuditRepository() {
return auditRepository;
}
...
}
#Entity
class AuditRepositoryEntity {
private List<AuditRecordEntity> auditRecords = new ArrayList<AuditRecordEntity>();
#OneToMany(mappedBy = "auditRepository")
public List<AuditRecordEntity> getAuditRecords() {
return auditRecords;
}
...
}
I have the following HQL query to get the latest (by accessTime) AuditRecord for each distinct Repository:
select auditRecord from AuditRecordEntity auditRecord where auditRecord.accessTime =
(select max(auditRecord2.accessTime) from AuditRecordEntity auditRecord2 where
auditRecord2.auditRepository = auditRecord.auditRepository)
I would like to know the equivalent SQL for the above HQL?
(the reason for this is I'l like to add the query as an sql restriction using the criteria API, as I am having trouble translating the HQL above to use the criteria API - see Hibernate criteria implementation for this entity model (subquery, self-join))
There is one hibernate property named
hibernate.show_sql
You can set it true in your hibernate configuration file or property file. It will show you the equivalent sql query of your hql/criteria query.