Hibernate how to ignore #Where annotation - java

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();

Related

Additional filter of entity in Spring data based on profile

I have a DB table, let's call it USERS. In this table, I have standard fields like name, surname, age, etc.
This table is mapped to the JPA entity class:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "login")
private String id;
#Column(name = "name")
private String name;
//etc...
}
Now I need to have the possibility to filter some of the users based on the environment. The environment can be defined based on the Spring active profile.
My assumption was to add the new DB column, let's say boolean filter, and based on the Spring profile to filter or not the user out.
The question is about the best way of implementation of this functionality so it would be clean and maintainable.
One way is to have two different #Repository and based on the profile init the right one. One repository will return all the users but the other one will return only the users with filter=false.
What I don't like about this implementation is that there will be a lot of code duplication. For each repository method, I will have to have the same method in the second repository, but with the filtering based on one column. Is there a way do define maybe some kind of `interceptor`` that will do it automatically for each read query on the given DB entity?
Not interceptor, but one can do it using jpa criteria: docs
This way you can dynamically configure what you want. Afaik, in runtime it would be a bit slower than plain old solution with several #Repository marked with #ConditionalOnProperty, or other bit of configuration of your choice, however, it meets your requirement of changing behavior without the need of introducing several repos. What you would want to do is declare Specification /default one and pass it around. This way you could later on also configure your search in runtime too.

How to customize hibernate #ElementCollection envers audit table name?

I'm currently using Hibernate & Envers version 5.2.9.Final. I want to use #ElementCollection with a custom table name for both the collection and the audit table.
What I know so far is that modifying default table names has a variety of annotations to work with: For the entity itself there are the annotations #Table and #SecondaryTable as well as the corresponding envers annotations #AuditTable and #SecondaryAuditTable. For changing the table name of an element collection there is the #CollectionTable annotaion. I have not been able to find a corresponding envers annotation so far. So my question is:
How can I change the name for a hibernate #ElementCollection envers audit table?
Additional info
In the hibernate envers ticket which tracks the adding of auditing support for element collections, the same question was asked back in 2013 but not answered.
A code snippet to make my setup clear:
#Entity
#Table(name = "\"user\"")
#SecondaryTable(name = "\"user_secondary\"")
#Audited
#AuditTable("\"user_audit\"")
#SecondaryAuditTable(secondaryTableName = "user_secondary",
secondaryAuditTableName = "\"user_secondary_audit\"")
public class User {
// ... stuff like id and other fields ...
#ElementCollection
#CollectionTable(name = "\"user_references\"")
private Map<String, Long> references = new HashMap<>();
// TODO FIXME how to get a custom name for the audit table?
// ... more stuff like getters and setters
}
Hibernate generates all tables as intended, yet the collecction audit table is named 'user_references_AUD' while I would like to get the name 'user_references_audit' like for the other tables.
I'm also aware of the global settings affecting the audit table prefix or suffix, but that is only a last resort for my use case.
Update
As suggested I added a feature request to Hibernate JIRA.
That is because Envers has no complement for #CollectionTable.
You are welcomed to add a JIRA requesting that we add a complementing annotation and I can look at what is needed to add the functionality. Just at a glance, it shouldn't require too much as it merely needs to feed into the generated Envers entity table name for the collection middle entity.

Use Spring Data JPA, QueryDSL to update a bunch of records

I'm refactoring a code base to get rid of SQL statements and primitive access and modernize with Spring Data JPA (backed by hibernate). I do use QueryDSL in the project for other uses.
I have a scenario where the user can "mass update" a ton of records, and select some values that they want to update. In the old way, the code manually built the update statement with an IN statement for the where for the PK (which items to update), and also manually built the SET clauses (where the options in SET clauses can vary depending on what the user wants to update).
In looking at QueryDSL documentation, it shows that it supports what I want to do. http://www.querydsl.com/static/querydsl/4.1.2/reference/html_single/#d0e399
I tried looking for a way to do this with Spring Data JPA, and haven't had any luck. Is there a repostitory interface I'm missing, or another library that is required....or would I need to autowire a queryFactory into a custom repository implementation and very literally implement the code in the QueryDSL example?
You can either write a custom method or use #Query annotation.
For custom method;
public interface RecordRepository extends RecordRepositoryCustom,
CrudRepository<Record, Long>
{
}
public interface RecordRepositoryCustom {
// Custom method
void massUpdateRecords(long... ids);
}
public class RecordRepositoryImpl implements RecordRepositoryCustom {
#Override
public void massUpdateRecords(long... ids) {
//implement using em or querydsl
}
}
For #Query annotation;
public interface RecordRepository extends CrudRepository<Record, Long>
{
#Query("update records set someColumn=someValue where id in :ids")
void massUpdateRecords(#Param("ids") long... ids);
}
There is also #NamedQuery option if you want your model class to be reusable with custom methods;
#Entity
#NamedQuery(name = "Record.massUpdateRecords", query = "update records set someColumn=someValue where id in :ids")
#Table(name = "records")
public class Record {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//rest of the entity...
}
public interface RecordRepository extends CrudRepository<Record, Long>
{
//this will use the namedquery
void massUpdateRecords(#Param("ids") long... ids);
}
Check repositories.custom-implementations, jpa.query-methods.at-query and jpa.query-methods.named-queries at spring data reference document for more info.
This question is quite interesting for me because I was solving this very problem in my current project with the same technology stack mentioned in your question. Particularly we were interested in the second part of your question:
where the options in SET clauses can vary depending on what the user
wants to update
I do understand this is the answer you probably do not want to get but we did not find anything out there :( Spring data is quite cumbersome for update operations especially when it comes to their flexibility.
After I saw your question I tried to look up something new for spring and QueryDSL integration (you know, maybe something was released during past months) but nothing was released.
The only thing that brought me quite close is .flush in entity manager meaning you could follow the following scenario:
Get ids of entities you want to update
Retrieve all entities by these ids (first actual query to db)
Modify them in any way you want
Call entityManager.flush resulting N separate updates to database.
This approach results N+1 actual queries to database where N = number of ids needed to be updated. Moreover you are moving the data back and forth which is actually not good too.
I would advise to
autowire a queryFactory into a custom repository
implementation
Also, have a look into spring data and querydsl example. However you will find only lookup examples.
Hope my pessimistic answer helps :)

Override #Where clause condition in Hibernate 4.3.4

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.

JPA fetch collection of subclass

I have a case where we have an inheritance strategy like this (this is an example of the jpa wiki, our real example is an other business case :))
#Entity
#Inheritance
#DiscriminatorColumn(name="PROJ_TYPE")
#Table(name="PROJECT")
public abstract class Project {
#Id
private long id;
...
}
#Entity
#DiscriminatorValue("L")
public class LargeProject extends Project {
#OneToMany
private Set<Member> members;
}
#Entity
#DiscriminatorValue("S")
public class SmallProject extends Project {
}
I have a bunch of projects in my database and want to fetch all the projects at once, but by doing this, i also want to fetch my list of members at once.
Is there a way to do this with jpql? I know the TYPE annotation allows me to look at the type, but can I combine this with a JOIN FETCH?
I'm using hibernate, but don't want to downgrade back to the hibernate api if I don't need to
JPA and Hibernate doesn't support fetching associations from subclasses, unless the property is also present in the topmost member of the hierarchy. But according to this post (https://thorben-janssen.com/fetch-association-of-subclass/) you can work around this limitation by exploiting hibernate's level 1 cache mechanism.
In you case you'll fetch all instances of Member first, in a separated query, and then perform your query on Project, letting LargeProject.members to be Lazy loaded. Instead of performing N + 1 SELECTs, hibernate will fetch those from the cache.
A bit late but I found a way by using only JPQL.
In your case :
SELECT p FROM Project p JOIN FETCH ((TREAT(p as LargeProject)).members)

Categories

Resources