How to access PostgreSQL RETURNING value in Spring Boot DAO? - spring

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?

Related

Spring JPA + H2 DB : Save field value case insensitive

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.

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 to filter a PageRequest in spring

When I make a request about all the news that I have in my database I use a PageRequest like this:
public Page<StatusUpdate> getPageSiteUser(int pageNumber) {
PageRequest request = new PageRequest(pageNumber-1, pageSize, Sort.Direction.DESC, "added");
return statusUpdateDao.findAll(request);
}
And it shows all the news in each page sorted in perfect order.
But now, I want to select the news created by one user, in the same Pageable format (not all the news) and I do not find how to do it, so I must be making a stupid mistake somewhere... it should be something like...
public Page<StatusUpdate> findMyStatusUpdates(Long user_id, int pageNumber) {
PageRequest request = new PageRequest(pageNumber-1, pageSize, Sort.Direction.DESC, "added");
return statusUpdateDao.findAll(request);
}
Please, answer with a link to the the theory if you can. The documentation talks about sorting, not making the actual selection (enter link description here)
You can combine a query, to filter by the user, with a pageable request. The query can be created by Spring based on the method name.
Take a look to the documentation:
Spring data JPA Query creation
Using Pageable, Slice and Sort in query methods
In your case, without seeing your code, I guess you only need to include in your repository a method like:
public interface StatusUpdateRepository extends Repository<StatusUpdate, Long> {
//finBy<column_name>
Page<User> findByUser(Long userId, Pageable pageable);
}
You can also send a PageRequest to an existing filter in your repo. You can create a repository method, filter them according to your business need.
Let's say you would like to find posts by supplying a user, status attributes and then order them by their creation date in descending order.
One might not desire all posts being included in the Page object while sending them to a Pager, before adding to the Model model.
This is simply equivalent to a sql query as such:
select * from Post where user=user and status=status order by createdAt desc
--
public interface BlogRepository extends PagingAndSortingRepository<Post, Long> {
Page<Post> findByUserAndStatusOrderByCreatedAtDesc(PageRequest pageRequest,
User user, boolean status);
}
and in your controller, use its implementation(postService) along with a new PageRequest object like:
Page<Post> filteredPosts = postService.findByUserAndStatusOrderByCreatedAtDesc(PageRequest.of(evalPage, evalPageSize), user, status);
this works fine for 2.x.x; whereas you better use below for 1.x.x
Page<Post> filteredPosts =
postService.findByUserAndStatusOrderByCreatedAtDesc(new PageRequest(evalPage,
evalPageSize), user, status);
This repo guided me up to a certain point on this matter with paging logic etc.
Just had to change from ModelView to Model in the controller's argument and returned String (template's name) instead.

Spring data JPA for returning specific fields

Does Spring Data have a mechanism for returning specific fields?
I'm familiar with the syntax:
Invoice findByCode(String code);
How about this:
Integer findIdByCode(String code);
which returns the id field only. Or
Tuple findIdAndNameByCode(String code);
which returns a tuple. Or
Invoice findIdAndNameByCode(String code);
which returns an entity only populated with specific fields. Can use a constructor taking only those field if defined - else construct empty and populate the fields.
EDIT
To qualify some more, I'm aware of solutions like #Query, constructor expressions and now, #NamedEntityGraph. My question is simply - does Spring data support such a shorthand syntax as I'm suggesting?
If not, perhaps this is a cool enhancement for a later version...
I'm not looking for workarounds.
You can use JPQL Constructor Expressions:
SELECT NEW com.company.PublisherInfo(pub.id, pub.revenue, mag.price)
FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
The constructor name must be fully qualified
If you want to return just 1 field from table and it's primitive(or autoboxing), you can use next:
#Query("select distinct t.locationId from Table t")
List<Long> findAllWashroomLocationId();
Where:
Table - name of class which represent your table
t - alias
locationId - name of field(in your Table object)
Long - type of locationId (Integer, String, ...)
Not sure if what you're trying to achieve is the same as using multiple projections on the same JPA generated query (where method name are the same). I have posted an answer in this post.
https://stackoverflow.com/a/43373337/4540216
So I've managed to figure out how to use multiple projections with a
single query.
<T> T getByUsername(String username, Class<T> projection) This allows the method caller to specified the type of projection to be
applied to the query.
To further improve this so it is less prone to error, I made a blank
interface that the projection will have to extend in order to be able
to insert class into the parameter.
public interface JPAProjection {
}
public interface UserRepository extends CrudRepository<UserAccount, Long> {
<T extends JPAProjection > T getByUsername(String username, Class<? extends JPAProjection> projection);
}
Projection Interface
public interface UserDetailsProjection extends JPAProjection{
#Value("#{target.username}")
String getUsername();
#Value("#{target.firstname}")
String getFirstname();
#Value("#{target.lastname}")
String getLastname();
}
Then I can call the query method by
getByUsername("...", UserDetailsProjection.class)
i have a nativequery,
this is a insert and i going to return all fields after insert whit "RETURNING *"
this query return all fields of my database, and this data going to save in my entity
"Perfil Detalles"
my entity have all configurations of my fields of my database
#Query(
value= "INSERT INTO \"USUARIO\".\"PERFIL_CONFIGURACION\" (id_perfil, id_group, id_role) VALUES(:id_perfil, :id_group, :id_role) returning *",
nativeQuery = true)
public PerfilDetalles insertPerfilDetalles(
#Param("id_perfil") Long id_perfil,
#Param("id_group") int id_group,
#Param("id_role") int id_role);

Resources