How to query for entities by their string collection values LIKE - spring-data

I have the following entity:
#Entity
public class SystemLogEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private long creationTime;
private String thread;
private int severity;
#Lob
private String message;
#ElementCollection(fetch = FetchType.EAGER)
#Lob
private List<String> stacktrace;
...
}
My Respository implements JpaSpecificationExecutor, which allows me to use Specifications to filter my db requests:
#Repository
public interface SystemLogRepository extends JpaRepository<SystemLogEntity, Long>, JpaSpecificationExecutor<SystemLogEntity> {
public List<SystemLogEntity> findAll(Specification spec);
}
For the simple field of the SystemLogEntity this works fine, the Predicate are straight forward.
Also if I filter for an exact item in a collection, the Predicate are still straight forward (in).
But how can I filter my SystemLogEntity after a stack trace collection item which is LIKE a given value?
In other words, I would e.g. like to filter SystemLogEntity after the term NullpointerException. Is this even possible with Predicate?

I hope this will work:
Specification<SystemLogEntity> stacktraceLike(String stacktrace) {
return (root, query, cb) -> cb.like(root.join("stacktrace"), "%" + stacktrace + "%");
}
More examples...

Related

Spring JPA query using specification and projection

I used spring jpa specification to build dynamically an entity query.
It's working perfect but the query returns all entity fields which makes the performance slower.
I want to fetch specific entity fields only and not fetching all entity fields and dependencies which I don't want and I will not use.
I search on the web, I tried some scenarios but without any lack.
Can anyone suggest any solution on this?
Thanks in advance
Here is what I have.I'm using spring boot 2.2.4
public class Concert {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#Column
private String code;
#Column
private double totalIncome;
#Column
private double totalExpenses;
#Column
private double totalBudget;
#ManyToOne(targetEntity = Orchestra.class, fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "orchestra_id")
private Orchestra orchestra;
#ManyToOne(targetEntity = ConcertStatus.class, fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "concert_status_id")
private ConcertStatus status;
/* other fields */
}
Specification:
public class ConcertSpecification implements Specification<Concert> {
#Override
public Predicate toPredicate(Root<Concert> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
//add add criteria to predicates
for (Criterion criteria : criteriaList) {
/* predicates builder here */
}
return builder.and(predicates.toArray(new Predicate[0]));
}
}
Repository:
public interface ConcertDao extends JpaRepository<Concert, Long>, JpaSpecificationExecutor<Concert>, PagingAndSortingRepository<Concert, Long> { }
ConcertService:
public interface ConcertService {
Page<Concert> findAll(#Nullable Specification<Concert> spec, Pageable pageable);
}
ConcertServiceImpl:
#Service(value = "concertService")
public class ConcertServiceImpl implements ConcertService {
public Page<Concert> findAll(#Nullable Specification<Concert> spec, Pageable pageable){
List<Concert> list = new ArrayList<>();
concertDao.findAll(spec).iterator().forEachRemaining(list::add);
return new PageImpl<Concert>(list);
}
}
Usage of projections with specifications are not supported and there is a PR for it that has been hanging for over five years.

Set vs List in REST One To Many

I have one to many relationship. If in class Customer I write List:
private List<Orders> order;
my GetMapping will work fine.
But I want to use best practices and I write Set instead of List:
private Set<Orders> order;
In result I have error:
Could not write JSON: Infinite recursion (StackOverflowError); nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
Infinite recursion (StackOverflowError)
Why I have this error? What's wrong with Set?
My entities:
#Entity
public class Customer {
#Id
#GeneratedValue
private int id;
private String firstName;
private String lastName;
#OneToMany(cascade=ALL, mappedBy="customer", orphanRemoval=true)
private Set<Orders> order;
//private List<Orders> order;
}
#Entity
public class Orders {
#Id
#GeneratedValue
private int id;
#JsonIgnore
#ManyToOne
#JoinColumn(name="customer_id", nullable=false)
private Customer customer;
}
And GetMapping:
#GetMapping("/customer/{id}")
public ResponseEntity get(#PathVariable Long id) {
Optional<Customer> customer = customerRepository.findById(id);
return new ResponseEntity<>(new ResponseObject(customer));
}
UPD. I see question Infinite Recursion with Jackson JSON and Hibernate JPA issue. But it's other question. I talk about difference in use List and Set. I am not interesting in #JsonIgnore and I don't ask about it (and I use it in my code). I want to understand why I have an error when I use Set and don't have error with List

Query in Spring JPA using List of two parameters

public interface InventoryRepository extends JPARepository<Inventory, Long> {
List<Inventory> findByIdIn(List<Long> ids);
}
Above is working fine, however in same way I am trying to fetch the List or Map, based on multiple params List ids and List sortNumber.
I would be also happy with return type Map from the method.
I came up with below things, which isn't correct.
List<Inventory> findByIdANDSortNumberIn(List<Long> ids, List<Long> sortNumbers);
Should do it with help of Criteria ? Is there any better way to do it?
Entity :
#Entity
#Table(name = Constants.T_INVENTROTY)
#Data
public class Inventory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = Constants.COLUMN_IN_DM)
private Long id;
#Column(name = Constants.COLUMN_PROD_DESCRIPTION)
private String prodDescription;
#Column(name = Constants.COLUMN_PROD_DESCRIPTION)
private Long sortNumber;
#Column(name = Constants.COLUMN_QUANTITY)
private long quantity
}
This should work
List<Inventory> findByIdInAndSortNumberIn(List<Long> ids, List<Long> sortNumbers);
You can specify And and do the same for multiple fields.

Query an embedded collection inside an entity using Datanucleus and mongodb

I was trying to query a embedded collection inside an entity using a query similar to the following:
Query q = em.createQuery("SELECT u FROM User u , in (u.addresses) a
WHERE a.state='xx'");
The query didn't return any result nor did it throw any error. I am using Datanucleus and MongoDb. Does Datanucleus have any limitation on such queries?
And the entity looked like:
public class User{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
protected long id;
#ElementCollection
protected List<Address> addresses;
public User(){
}
...
#Embeddable
public class Address {
private String street;
private String city;
private String state;
private Integer zip;
public Address(){
}
...

Hibernate-search search from any indexed entity

I am using Hibernate-search for searching data in my Jboss application. I have 3 JPA entity classes that all extend BaseEntity class and each are indexed by Lucene. For example:
#MappedSuperclass
public abstract class BaseEntity implements Serializable {
#Temporal(TemporalType.TIMESTAMP)
private Date created;
public abstract Long getId();
}
#Entity
#Table(name = "DVD")
public class Dvd extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Field
private String title;
}
#Entity
#Table(name = "BOOK")
public class Book extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Field
private String author;
}
Now I would like to search for either DVD title or Book author by wildcard search query and get the result list as List. This is what I have this far:
public List<BaseEntity> search(String query, int firstResult, int maxResults) {
List<BaseEntity> results = null;
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
Query luceneQuery = new WildcardQuery(new Term("*", "*" + query + "*"));
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, BaseEntity.class);
fullTextQuery.setFirstResult(firstResult);
fullTextQuery.setMaxResults(maxResults);
results = fullTextQuery.getResultList();
return results;
}
But with this I am not getting any results. How is it possible to get this to work or is there even way without using buildQueryBuilder for each entity? Thanks!
You'll want to use the varargs-style method for the classes, like so:
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, DVD.class, Book.class);
This is because when Hibernate Search creates the search query, it adds the class name(s) to the query (for the _hibernate_class field, which is the indexed class' name).