I have a sample code piece like this-
#Entity
#Table(name = "employee")
#Where(clause = "active IS TRUE")
public class Employee{
}
This will fetch all the record of employee table having active=true or 1. In some cases, it may require that I want to load the records having active=false or 0.
If I write my code as FROM Employee emp WHERE emp.active IS FALSE but the generated query contains bot the conditions given in HQL and Annotations.
Hence, the expected results is not coming. Is there anyway to override this predefined #Where defined over entity?
I know its too old question but I was facing same issue and thought I should share my workaround.
Totally agree with #cнŝdk answer as you cannot override but you can ignore #Where clause by defining nativeQuery as below:
#Query(value = "Select * from customer where company_id = ?1", nativeQuery = true) List<Customer> findByCompanyIdIgnoringEntityWhere(Long companyId);
The SQL in the #Query annotation must point the table's name and the fields' names (not entity's name).
AFAIK you can't override it inside your class because if you take a look at the #Where documentation you will see that this interface is annotated #Retention(value=RUNTIME) so it has RUNTIME as a RetentionPolicy and you can see in the RetentionPolicy documentation that:
RUNTIME:
Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
Which force the #Where annotation to be recorded in the class file by the compiler and retained by the VM at run time, so it will be applied all over this class.
Related
I am having some trouble with creating an #interface which combines some others in it.
For an example I want to create an #Interface and pass a parameter to it which will automatically be given/passed to its "parents".
As far as I know, this can not be done. But I am still curious if there is anything I could do.
#Entity(name = "categories")
#Where(clause = "deleted=0")
#SQLDelete(sql = "UPDATE categories SET deleted = 1 WHERE id = ? AND version = ?")
public class Category extends BaseEntity {
In the code above you can see that the parameter "name" which has value "categories" is used in the Entity annotation and it is also contained in the string of the SQLDelete.
Doing this, I want to make the code more readable, and avoid having too many Annotations which are the same for all of the entities I have. Also if I need to change an annotation for all of them to be able to make it easier.
Imagine the following scenario where we use inheritance strategy TABLE_PER_CLASS and Template as superclass while Product as subclass.
Template:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "Templates")
#NamedQuery(name = "getAllTemplates", query = "SELECT t FROM Template t")
public class Template implements Serializable { ...}
Product:
#Entity
#Table(name = "Product")
public class Product extends Template implements Serializable { ... }
In this scenario even thought i have in my DB 2 templates and 1 product. Whenever i call the Template namedQuery i retrieve both Products and Templates alike.
I tried do something like so:
SELECT t FROM Template t WHERE TYPE(t) = Template
However it returns the following error:
The class does not have a descriptor, or a descriptor that does not use inheritance or uses a ClassExtractor for inheritance
Is there a way to only get the Templates?
The TYPE operator does not work for sub classes either when using TABLE_PER_CLASS. There seems not to be explicit information about using TYPE with TABLE_PER_CLASS.
However there are lots of posts saying that this strategy is inefficient and not exactly recommended to be used.
JPA 2.1 specifications say about TABLE_PER_CLASS:
Support for the TABLE_PER_CLASS mapping strategy is optional in this release.
This means also that support might be only partial: like TYPE support not implemented.
Also there are some posts that indicate that not only Hibernate suffers from this, see (some pretty old, but still), like: this and this.
So as a conclusion:
change to SINGLE_TABLE or JOINED strategy if possible
live with it
In Hibernate you could also try to get it working with #DiscriminatorColumn and adding the column to Template entity but I personally think it is not worth the effort.
I have an entity:
#Entity
#Table(name = "[Usermaster]")
#Where(clause = "isDeleted = 0")
public class User {
//...
}
in some flow I need to ignore #Where annotation and get user even if isDeleted is not 0. How can I make it? (I use CRUD repositories to query)
There is a dynamic version of the #Where setting, it is the #Filter. See:
19.1. Hibernate filters
Hibernate has the ability to pre-define filter criteria and attach those filters at both a class level and a collection level. A filter criteria allows you to define a restriction clause similar to the existing "where" attribute available on the class and various collection elements.
Management of #Filter is a bit more complex, in a nutshell:
<filter-def> / #FilterDef is needed to define filter
<filter> / #Filter must be assigned to class or a set
filter must be enabled on a session level, e.g.: session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");
So, this, while being a bit more complex, provides exactly what we need: dynamic #Where to be turned on/off in run-time
Old question, but the answer might be here:
simple solution is to use native SQL:
lst = sessionFactory.getCurrentSession().
createSQLQuery("select {entb.*} from EntityB entb where is_deleted=1")
.addEntity("entb", EntityB.class)
.list();
I'm using Hibernate 3.2.2 GA with HSQLDB 2.0 GA, and I have a class hierarchy similar to the following:
#Entity
#Table(name = "A_TABLE")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorFormula(value = "case when CODE IN (1, 2, 3, 4) then 'TypeB'
when CODE IN (5, 6, 7, 8) then 'TypeC' else NULL end")
#org.hibernate.annotations.Entity(dynamicUpdate = true, dynamicInsert = true)
public abstract class A{
(...)
}
#Entity
#DiscriminatorValue("TypeB")
public class B extends A {
(...)
}
#Entity
#DiscriminatorValue("TypeC")
public class C extends A {
(...)
}
I'm trying to execute the following HQL query, which returns objects from both B and C classes.
String hql = "from A a where a.someAttr = 3";
Query query = session.createQuery(hql);
return query.list();
However, I get the following error:
org.hibernate.WrongClassException: Object with id: 2 was not of the specified subclass: A (Discriminator: C )
The strangest thing is that the object with id 2 is a C instance...
I've googled for this error and I've found some people who's faced it, none using InheritanceType.SINGLE_TABLE and DiscrimatorFormula, though. Has anyone run into this problem?
Make sure the entity is listed in your config file (persistence.xml, for example). From https://stackoverflow.com/a/14150629/116596
The problem is that you're getting a list of A's and Hibernate doesn't know enough to create B's or C's in a list based on the discriminator formula. Luckily, there's an annotation to deal with this.
Some people call this a bug, and I'm sort of inclined to agree. At any rate, the abstraction seems to be a bit leaky.
Add a #ForceDiscriminator annotation to the parent entity (A) and it's likely to work properly.
This solution is Hibernate-specific. I'm not sure if the problem extends to JPA in general or if there's a JPA solution.
EDIT:
This appears not to have done the trick.
It might be worthwhile to try to get the sql that hibernate is generating for you.
Add
<property name="hibernate.show.sql" value="true" />
to your hibernate config and see what happens.
Getting this sql with and without the force clause might give clues as to exactly what the force does and why it's not working.
I can't think of anything else at the moment, except the NULL in your discriminator formula looks a little risky.
Well, this got me curious: it may be you suffer from this issue which says:
The reason is the string is interpreted as a CHAR type rather than
VARCHAR. We may change this behaviour in the future.
Can you try to apply TRIM() on the result (inside the #DiscriminatorFormula) or test with another DBMS? This doesn't seem to be Hibernate specific.
I solved it using the DTYPE column and WHERE clause.
With your example, it would be:
#Entity
#WHERE(clause = "DTYPE = 'B'")
public class B extends A {
...
}
#Entity
#WHERE(clause = "DTYPE = 'C'")
public class C extends A {
...
}
What exactly does JPA's fetch strategy control? I can't detect any difference between eager and lazy. In both cases JPA/Hibernate does not automatically join many-to-one relationships.
Example: Person has a single address. An address can belong to many people. The JPA annotated entity classes look like:
#Entity
public class Person {
#Id
public Integer id;
public String name;
#ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
#Entity
public class Address {
#Id
public Integer id;
public String name;
}
If I use the JPA query:
select p from Person p where ...
JPA/Hibernate generates one SQL query to select from Person table, and then a distinct address query for each person:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
This is very bad for large result sets. If there are 1000 people it generates 1001 queries (1 from Person and 1000 distinct from Address). I know this because I'm looking at MySQL's query log. It was my understanding that setting address's fetch type to eager will cause JPA/Hibernate to automatically query with a join. However, regardless of the fetch type, it still generates distinct queries for relationships.
Only when I explicitly tell it to join does it actually join:
select p, a from Person p left join p.address a where ...
Am I missing something here? I now have to hand code every query so that it left joins the many-to-one relationships. I'm using Hibernate's JPA implementation with MySQL.
Edit: It appears (see Hibernate FAQ here and here) that FetchType does not impact JPA queries. So in my case I have explicitly tell it to join.
JPA doesn't provide any specification on mapping annotations to select fetch strategy. In general, related entities can be fetched in any one of the ways given below
SELECT => one query for root entities + one query for related mapped entity/collection of each root entity = (n+1) queries
SUBSELECT => one query for root entities + second query for related mapped entity/collection of all root entities retrieved in first query = 2 queries
JOIN => one query to fetch both root entities and all of their mapped entity/collection = 1 query
So SELECT and JOIN are two extremes and SUBSELECT falls in between. One can choose suitable strategy based on her/his domain model.
By default SELECT is used by both JPA/EclipseLink and Hibernate. This can be overridden by using:
#Fetch(FetchMode.JOIN)
#Fetch(FetchMode.SUBSELECT)
in Hibernate. It also allows to set SELECT mode explicitly using #Fetch(FetchMode.SELECT) which can be tuned by using batch size e.g. #BatchSize(size=10).
Corresponding annotations in EclipseLink are:
#JoinFetch
#BatchFetch
"mxc" is right. fetchType just specifies when the relation should be resolved.
To optimize eager loading by using an outer join you have to add
#Fetch(FetchMode.JOIN)
to your field. This is a hibernate specific annotation.
The fetchType attribute controls whether the annotated field is fetched immediately when the primary entity is fetched. It does not necessarily dictate how the fetch statement is constructed, the actual sql implementation depends on the provider you are using toplink/hibernate etc.
If you set fetchType=EAGER This means that the annotated field is populated with its values at the same time as the other fields in the entity. So if you open an entitymanager retrieve your person objects and then close the entitymanager, subsequently doing a person.address will not result in a lazy load exception being thrown.
If you set fetchType=LAZY the field is only populated when it is accessed. If you have closed the entitymanager by then a lazy load exception will be thrown if you do a person.address. To load the field you need to put the entity back into an entitymangers context with em.merge(), then do the field access and then close the entitymanager.
You might want lazy loading when constructing a customer class with a collection for customer orders. If you retrieved every order for a customer when you wanted to get a customer list this may be a expensive database operation when you only looking for customer name and contact details. Best to leave the db access till later.
For the second part of the question - how to get hibernate to generate optimised SQL?
Hibernate should allow you to provide hints as to how to construct the most efficient query but I suspect there is something wrong with your table construction. Is the relationship established in the tables? Hibernate may have decided that a simple query will be quicker than a join especially if indexes etc are missing.
Try with:
select p from Person p left join FETCH p.address a where...
It works for me in a similar with JPA2/EclipseLink, but it seems this feature is present in JPA1 too:
If you use EclipseLink instead of Hibernate you can optimize your queries by "query hints". See this article from the Eclipse Wiki: EclipseLink/Examples/JPA/QueryOptimization.
There is a chapter about "Joined Reading".
to join you can do multiple things (using eclipselink)
in jpql you can do left join fetch
in named query you can specify query hint
in TypedQuery you can say something like
query.setHint("eclipselink.join-fetch", "e.projects.milestones");
there is also batch fetch hint
query.setHint("eclipselink.batch", "e.address");
see
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html
I had exactly this problem with the exception that the Person class had a embedded key class.
My own solution was to join them in the query AND remove
#Fetch(FetchMode.JOIN)
My embedded id class:
#Embeddable
public class MessageRecipientId implements Serializable {
#ManyToOne(targetEntity = Message.class, fetch = FetchType.LAZY)
#JoinColumn(name="messageId")
private Message message;
private String governmentId;
public MessageRecipientId() {
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
public String getGovernmentId() {
return governmentId;
}
public void setGovernmentId(String governmentId) {
this.governmentId = governmentId;
}
public MessageRecipientId(Message message, GovernmentId governmentId) {
this.message = message;
this.governmentId = governmentId.getValue();
}
}
Two things occur to me.
First, are you sure you mean ManyToOne for address? That means multiple people will have the same address. If it's edited for one of them, it'll be edited for all of them. Is that your intent? 99% of the time addresses are "private" (in the sense that they belong to only one person).
Secondly, do you have any other eager relationships on the Person entity? If I recall correctly, Hibernate can only handle one eager relationship on an entity but that is possibly outdated information.
I say that because your understanding of how this should work is essentially correct from where I'm sitting.