Spring JPA + H2 DB : Save field value case insensitive - spring

I am writing a Spring Boot application using Spring JPA and H2 DB. In an entity user, I want to save the field userId with unique values in case insensitive manner.
So once the user inserts userId as user1, he must not be allowed to save another userId as User1.
One possible way is to make the user entity's getters read value in lower/upper case and the setters write the value in lower/upper case, as below :
public String getUserId() {
return userId.toLowerCase();
}
public void setUserId(String userId) {
this.userId = userId.toLowerCase();
}
Is there an alternate/better solution, preferably at schema level?

I'm not sure how to configure it with annotations, but if you create your schema manually and can control the script you can use varchar_ignorecase for the column. Then you can store your data in mixed case, but any database constraints you create and indeed any comparisons will ignore case.

Related

How to access PostgreSQL RETURNING value in Spring Boot DAO?

I want to return the auto-generated id of entity. PostgeSQL is able to automaticaly selects certain column via RETURNING, but I have a hard time trying to find how to retrieve this value in Spring Boot.
I would want something like:
public int createUser(User user) {
String sql = "INSERT INTO user (name, surname) VALUES (?,?) RETURNING id";
return jdbcTemplate.update(sql,
user.getName(),
user.getSurname(),
resultSet -> resultSet.getInt("id")
);
}
I know it's straightforward in Hibernate, then whether you use a Repository class or an EntityManager, the save method returns the saved entity, so you can just do:
int id = userRepository.save(user).getId();
Or is there a reason you want to persist it the way you do?

How to give dynamic value to #Table(name=p+"name") in spring JPA

name of the table should be fixed but in my scenario the last part of the table name is profile based so in local it is X but in dev it is Y and so on till Prod. Is there way to add dynamically the value to the table name.
The question tries to implement a bad practice. Don't do that.
Currently, Spring, Hibernate, and JPA does not support your configuration type.
You can use Hibernate interceptors to change the table in the generated SQL statements.
For your case you can define your table class like this:
#Entity
#org.hibernate.annotations.Proxy(lazy=false)
#Table(name=TableNameReplacer.PLACEHOLDER, schema="MySchema")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class ProfileData implements Serializable {
and define your Hibernate interceptor in a following way:
public class TableNameReplacer extends EmptyInterceptor {
public static final String TABLE_PLACEHOLDER = "{table_placeholder}";
#Override
public String onPrepareStatement(String sql) {
if (sql.contains(TABLE_PLACEHOLDER )) {
String replacement = "{your logic to fill proper table name}";
sql = sql.replace(TABLE_SUFFIX_PLACEHOLDER, replacement);
}
return super.onPrepareStatement(sql);
}
Using this approach you're free to modify generated SQL and replace the table name there as you wish.
I recommend to use good placeholder value which you're sure will not be a part of actual values being saved to the table (or you can only limit this to select statements if you only read the data).

Tenant Id filter where Multi-tenancy in single database

I'm using JDBCTemplate and not using Hibernate and running native SQL queries.
I need to attach/append tenant id to any query which is being executed.
For multiple database i come across this - https://github.com/openMF/mifosx-admin/blob/master/src/main/java/org/mifosx/admin/domain/BaseDAO.java
Can someone help me with suggestion or comments how to attach the tenant id dynamically as jdbc interceptor or apply filter for queries?
Currently all queries goes like select * from...where tenant id = test
Thanks.
Store the tenant id as soon as you can determine it's value, in a thread-local, perhaps facilitated by a servlet filter.
If all such entities implement an interface which exposes a 'tenantId' property, Then update this property in your entity objects, from the above thread-local tenantId, in your BaseDAO class.
By way of example, you could create a singleton which keeps a threadlocal copy of your tenant id, assuming that it is an Integer. Here's one way to do this.
public enum ThreadState {
INSTANCE
;
private ThreadLocal<Integer> tenantId = new ThreadLocal<>();
public void setTenantId(Integer tid) {
tenantId.set(tid);
}
public Integer getTenantId() {
return tenantId.get();
}
}
Then, in that place in your code where you determine what the tenant ID is for the given request, stash it into our new threadlocal as follows:
ThreadState.INSTANCE.setTenantId(tenantId);
And finally, in your DAO class where you are formulating a query and need to access the tenant ID write the following:
Integer tenantId = ThreadState.INSTANCE.getTenantId()
At this point you can use the tenantId when formulating your query, or update a new entity object prior to storing it.

How do I migrate my JPA DAO to Spring Data with second level cache?

I have bunch of JPA DAOs im looking to migrate to Spring Data JPA. Some of my DAOS have second-level / query caching set up.
I have a process where I only retrieve the ID in my queries, and then look up the entity using findByID(). This way, only the id's are multiplied in the different query caches, and the entire entities are in the second level cache.
Example:
#NamedQuery(name = "SystemUser.findByEmail",
query = "SELECT u.id FROM SystemUser u WHERE email=:email"),
…
public SystemUser findByEmail(String email) {
TypedQuery<Long> q = getEntityManager().createNamedQuery("SystemUser.findByEmail", Long.class);
q.setParameter("email", email);
q.setHint("org.hibernate.cacheable", true);
q.setHint("org.hibernate.cacheRegion", "query.systemUser");
List<Long> res = q.getResultList();
if (res != null && res.size() > 0) {
return findById(res.get(0));
}
return null;
}
I have several more findBy…-methods, all doing it like this. It feels like a good way to keep cache memory consumption down.
I'm kind of new to the Spring Data JPA business, but I can't see how I would go about realizing this here? The #Cacheable annotations seems only to deal with query caches, which to me would duplicate the entities in each query cache?
Is there any way to do this with Spring Data? Pointers would be much appreciated.
In Spring Data JPA just create a findByEmail method and either Spring Data JPA will found your named query or create one itself.
public class SystemUserRepository extends CrudRepository<SystemUser, Long> {
SystemUser findByEmail(String email);
}
Should be all you need to get the query executed and the desired result. Now with the #QueryHints you can add the hints you are setting now.
public class SystemUserRepository extends CrudRepository<SystemUser, Long> {
#QueryHints(
#QueryHint(name="org.hibernate.cacheable", value="true"),
#QueryHint(name="org.hibernate.cacheRegion", value="query.systemUser") )
SystemUser findByEmail(String email);
}
The result will be cached and still the user will come from the 2nd level cache (if available, else created). Assuming of course your entity is #Cacheable.
A nice read on how the 2 different caches work (together) can be found here. A small snippet on how the query cache works.
The query cache looks conceptually like an hash map where the key is composed by the query text and the parameter values, and the value is a list of entity Id's that match the query:
If you want more complex logic (and really implement the optimization you did) you can always implement your own repository.

Avoid N+1 with DTO mapping on Hibernate entities

In our Restful application we decided to use DTO's to shield the Hibernate domain model for several reasons.
We map Hibernate entities to DTO and vice versa manually using DTOMappers in the Service Layer.
Example in Service Layer:
#Transactional(readOnly=true)
public PersonDTO findPersonWithInvoicesById(Long id) {
Person person = personRepository.findById(id);
return PersonMapperDTOFactory.getInstance().toDTO(person);
}
The main concept could be explained like this:
JSON (Jackson parser) <-> Controller <-> Service Layer (uses Mapping Layer) <-> Repository
We agreed that we retrieve associations by performing a HQL (or Criteria) using a left join.
This is mostly a performant way to retrieve relations and avoids the N+1 select issue.
However, it's still possible to have the N+1 select issue when a developer mistakenly forgets to do a left join. The relations will still be fetched because the PersonDTOMapper will iterate over the Invoices of a Person for converting to InvoiceDTOs. So the data is still fetched because the DTOMapper is executed where a Hibernate Session is active (managed by Spring)
Is there some way to make the Hibernate Session 'not active' in our DTOMappers? We would face a LazyInitializationException that should trigger the developer that he didn't fetch some data like it should.
I've read about #Transactional(propagation = Propagation.NOT_SUPPORTED) that suspends the transaction. However, I don't know that it was intended for such purposes.
What is a clean solution to achieve this? Alternatives are also very welcome!
Usually I use the mapper in the controller layer. From my prspective, the service layer manages the application business logic, dtos are very useful if you want to rapresent data to the external world in a different way. In this way you may get the lazy inizitalization excpetion you are looking for.
I have one more reason to prefer this solution: just image you need to invoke a public method inside a public method in the service class: in this case you might need to call the mapper several times.
If you are using Hibernate, then there are specific ways that you can determine if an associated object has been lazy-loaded.
For example, let's say you have an entity class Foo that contains a #ManyToOne 'foreign' association to entity class Bar which is represented by a field in Foo called bar.
In you DTO mapping code you can check if the associated bar has been lazy-loaded using the following code:
if (!(bar instanceof HibernateProxy) ||
!((HibernateProxy)bar).getHibernateLazyInitializer().isUninitialized()) {
// bar has already been lazy-loaded, so we can
// recursively load a BarDTO for the associated Bar object
}
The simplest solution to achieve what you desire is to clear the entity manager after querying and before invoking the DTO mapper. That way, the object will be detached and access to uninitialized assocations will trigger a LazyInitializationException instead.
I felt your pain as well which drove me to developing Blaze-Persistence Entity Views which allows you to define DTOs as interfaces and map to the entity model, using the attribute name as default mapping, which allows very simple looking mappings.
Here a little example
#Entity
class Person {
#Id Long id;
String name;
String lastName;
String address;
String city;
String zipCode;
}
#EntityView(Person.class)
interface PersonDTO {
#IdMapping Long getId();
String getName();
}
Querying would be as simple as
#Transactional(readOnly=true)
public PersonDTO findPersonWithInvoicesById(Long id) {
return personRepository.findById(id);
}
interface PersonRepository extends EntityViewRepository<PersonDTO, Long> {
PersonDTO findById(Long id);
}
Since you seem to be using Spring data, you will enjoy the spring data integration.

Resources