Spring DATA JPA how to write a method which use contant value for a field to fetch data - spring

Hi I am using Spring Data JPA and want to use feature generate query from method name. I have a field active in DB which have only value 0 and 1. I want to fetch all data with which have active value is 1.
This is a constant value so i don't want to pass this value as method arguments.
please suggest what will be the method for the same.
example:
I have a entity EmailRef
public class EmailRef {
/* other vareialbe */
#Column(name="is_active") /* this is the field which value is 0 and 1 in DB*/
private Integer active;
/* setter getter method */
}
This is the repository for where I want to write method which will fetch all data for which active is 1;
public interface EmailRefRepositry extends JpaRepository<EmailRef, Long> {
#Query("select * from email_reference where is_active=1") /* this is the query I want to convert into method*/
List<EmailRef> findByActive(); /*I want to write method like that which will fetch all data form table where active field value is 1*/
}
I am stuck for constant vale please suggest
Thanks
Sudhanshu

If you could change that Integer to a boolean, you could be doing something like:
In your entity:
private Boolean active;
In your repo:
List<EmailRef> findByActiveIsTrue();

Try this:
public interface EmailRefRepositry extends JpaRepository<EmailRef, Long> {
#Query("select e from EmailRef e where e.active=1")
List<EmailRef> findOnlyActiveWithQuery();
default List<EmailRef> findOnlyActive() {
findByActive(1);
}
default List<EmailRef> findNotActive() {
findByActive(0);
}
List<EmailRef> findByActive(Integer active);
}

I don't think you can do what you want using Spring JPAs magic where is derives the query from the method name (unless you are able to do as #kimy82 suggests in their solution). You can of course use the #Query annotation on your repository method though. However the one you have defined won't work because it is a native query and you have no specified that. Here are two possible fixes to your Query annotation although I would recommend the first:
#Query("select e from EmailRef e where e.active=1")
or
#Query("select * from email_reference where is_active=1", nativeQuery=true)

Related

Custom update in CrudRepository

is that possible to returns updated entity by custom update method instead of numbers of affected rows? How can I achieve this?
I would like to have sth like this:
public interface DataRepository extends CrudRepository<Data, Long> {
#Modifying
#Query(value="UPDATE data SET max_version = max_version + 1 WHERE id = 'A'", nativeQuery=true)
Data updateDataByType();
}
instead of this
public interface DataRepository extends CrudRepository<Data, Long> {
#Modifying
#Query(value="UPDATE data SET max_version = max_version + 1 WHERE id = 'A'", nativeQuery=true)
Integer updateDataByType();
}
You cannot do this with the #Modifying annotation. because these methods can only be void and int. Otherwise you will get the error Modifying queries can only use void or int / Integer as return type.
But can be you can implement custom repository Implementation and return your updated entity after done with the query execution.
Reference: Custom Implementations for Spring Data Repositories

How to get the specific property value from .properties file in Spring Data Repository interface method #Query

I am able to get the property value in Spring classes like below:
#Value("${database.name}")
private String databaseName;
I have to execute a native query by joining different tables which are in different databases.
#Query(value="select t1.* FROM db1.table1 t1 INNER JOIN db2.table2 t2 ON t2.t1_id1 = t1.id1")
Instead of hard coding database names i.e., db1 and db2 here, I have to get them from properties file.
how to get the property value inside the #Query annotation in Spring Data JPA Repository ?
I don't know if it is possible, but if not, you can consider this approach:
Instead of using properties in Repository's #Query directly, you can use params in the query but when you call the actual method - you can provide values from .properties.
Imagine you have simple repository:
public interface UserRepository extends JpaRepository<User, Long> {
// query with param
#Query("select u from User u where u.lastname = :lastname")
User findByLastname(#Param("lastname") String lastname);
}
Then, let's say you have some Service or Controller where you need to use your Repository - you can inject properties there and pass them to your method:
#Service
public class UserService {
// this comes from .properties
#Value("${user.lastName}")
private String userLastName;
#Autowired
private UserRepository userRepository;
public User getUser() {
// you pass it as param to the repo method which
// injects it into query
return userRepository.findByLastname(userLastName);
}
}
This is just an example. But I believe it may be useful.
Happy hacking :)

How to Define Dynamic Model in Spring Framework

I am using Spring Framework as my back end
I have define know as Entity class The Entity class know contain 5 Fields
Below is the class , The code below dose not have setter getter part to make shorter and cleaner
#Entity
#Table(name="TblKnow")
public class Know {
#Id
private Double idKnow;
private String SubjectKnow;
private String BodyKnow;
private String ImgKnow;
private double CountView;
In JpaRepository interface i want to only query two column not all of columns.
public interface KnowRepository extends JpaRepository<Know,Double> {
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
Problem: i try to run but i get below exception
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]
But if i use without below query it is fine
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
You can create a custom constructor and use that to select only some fields in JPA query.
public Know(Double idKnow, String SubjectKnow) {
this.idKnow = idKnow;
this.SubjectKnow = SubjectKnow;
}
And the use this constructor in JPA query. Make sure you use complete path of class with package.
#Query("SELECT NEW packagePath.Know(idKnow,SubjectKnow) FROM Know")
query :
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
works dut to you select Know objects with fields that are mapped correct into Know class (and after wrapped into Page).
with query :
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
returns some custome bean/object that spring data can't map in correct way into Know class (as you declared it as expected return class wrapped into Page). add counstructor into Know with idKnow,SubjectKnow fields , or you can wrap it into some DTO with idKnow,SubjectKnow fields.

How to generate a value for a column in a JPA entity, while querying the database?

I have an entity that looks like this:
#Entity
#Table(uniqueConstraints={#UniqueConstraint(columnNames={"slug"})})
public class BlogPost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String title;
#Column
private String slug;
}
I would like to generate the value of slug before persisting by doing the following:
Transforming the title from e.g. Blog Post Title to blog-post-title
Making sure that blog-post-title is unique in table BlogPost, and if it's not unique, I want to append some suffix to the title so it becomes e.g. blog-post-title-2
Since I need this on a lot of entities, my original idea was to create an EntityListener which would do this at #PrePersist. However, documentation generally states that I should not call EntityMan­ager or Query methods and should not access any other entity objects from lifecycle callbacks. I need to do that in order to make sure that my generated slug is indeed unique.
I tried to be cheeky, but it is indeed very hard to autowire a repository into an EntityListener with Spring anyway.
How should I best tackle this problem?
Thanks!
Both OndrejM and MirMasej are definitely right that generating a slug would not be something to be done in an Entity. I was hoping EntityListeners could be a little "smarter", but that's not an option.
What I ended up doing is using aspects to accomplish what I wanted. Instead of "hooking" into entities, I am rather hooking into save method of CrudRepository.
First, I created an annotation so I can recognize which field needs to be sluggified:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Slug {
/**
* The string slug is generated from
*/
String source() default "title";
/**
* Strategy for generating a slug
*/
Class strategy() default DefaultSlugGenerationStrategy.class;
}
Then, I created an aspect which is something like this:
#Aspect
#Component
public class SlugAspect {
... // Removed some code for bravity
#Before("execution(* org.springframework.data.repository.CrudRepository+.save(*))")
public void onRepoSave(JoinPoint joinPoint) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Object entity = joinPoint.getArgs()[0];
for (Field field: entity.getClass().getDeclaredFields()) {
Slug annotation = field.getAnnotation(Slug.class);
if (annotation != null) {
CrudRepository repository = (CrudRepository) joinPoint.getTarget();
Long count = 0L;
SlugGenerationStrategy generator = (SlugGenerationStrategy)annotation.strategy().newInstance();
String slug = generator.generateSlug(slugOrigin(entity));
if (id(entity) != null) {
Method method = repository.getClass().getMethod("countBySlugAndIdNot", String.class, Long.class);
count = (Long)method.invoke(repository, slug, id(entity));
} else {
Method method = repository.getClass().getMethod("countBySlug", String.class);
count = (Long)method.invoke(repository, slug);
}
// If count is zero, use the generated slug, or generate an incremented slug if count > 0 and then set it like so:
setSlug(entity, slug);
}
}
}
}
I put the code on github (though it's still just a proof of concept) if anyone is interested at: https://github.com/cabrilo/jpa-slug
It relies on having CrudRepository from Spring Data and having these two methods on a repo: countBySlug and countBySlugAndIdNot.
Thanks again for the answers.
The most straightforward solutions seems to make a check before setting the value of the title. It would mean however that the logic of calculating the slug would be outside of the entity and both would come from outside.
You have to think of an entity as a plain object without any connection to the database - this is the idea of ORM. However, you may pass a reference to EntityManager or DAO as an additional argument to a setter method, or somehow inject a reference to it. Then you may call a query directly from the setter method. The drawback of this solution is that you need to always provide EntityManager, either when you set title, or when you create/load the entity.
This is the best object oriented way of solving this problem.

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