Does Hibernate Search work on fields annotated with JPA Converter - hibernate-search

I am storing few fields as JSON using JPA Converter annotation, does Hibernate Search provide support for indexing/searching these fields?

Hibernate Search doesn't see the "converted" side of your properties (in this case, the JSON).
If you have this:
#Convert(class = MyJsonConverter.class)
private MyObject myObject;
Then all Hibernate Search will see is an instance of MyObject. You can use #Field or #IndexedEmbedded as you would with any other property.

#Column(name="address")
#Convert(class = AddressConverter.class)
private Address fieldAddress;
If you convert your object to String for example. You can use something like with CriteriaBuilder
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeObject> query = cb.createQuery(SomeObject.class);
Root<SomeObject> from = query.from(SomeObject.class);
query.select(from).where(cb.equal(root.get("fieldAddress").as(String.class), "address in string"));
If you using Spring Data JPA, your way is using #Query
#Query(select * from SOME_TABLE where ADDRESS = ?1, nativeQuery = true)
List<SomeObject> findAllByMyObj(String address);
P.S. If you using Metamodel and you should to save consistent of your Query(check the documentations Hibernate JPA static metamodel generator), it would looks like
query.select(from).where(cb.equal(root.get(SomeObject_.fieldAddress).as(String.class), "address in string"));

Related

Exception when using a #ResultSetMapping on a native SQL query with a Spring Data JPA Repository?

I'm currently building a native SQL query with Spring Data JPA that uses a #SqlResultSetMapping. The query looks filters the rows based on certain parameters and then returns all of the columns of an entity table plus additionally it calculates another column on the fly. Something like this:
#Entity
#NamedNativeQuery(
name = "Entity.searchBySearchParams",
resultSetMapping = "SearchResultMapping",
query = "select entity.*, (*calculation*) as anotherField from ..."
)
#SqlResultSetMapping(
name = "SearchResultMapping",
entities = #EntityResult(entityClass = Entity.class),
columns = #ColumnResult(name = "anotherField", type = double.class)
)
public class Entity { ... }
And then I'm trying to call this native, named query from my repository (which extends JpaRepository<T, Long>) like that:
#Query(nativeQuery = true, name = "Entity.searchBySearchParams")
List<Object[]> searchBySearchParams( ... lots of params ... );
Where I'm expecting searchBySearchParams(...)[0] to be of type Entity and searchBySearchParams(...)[1] of type Double.
Unfortunately I'm getting this exception when trying to call the above repository method:
org.springframework.dao.InvalidDataAccessApiUsageException: Cannot create TypedQuery for query with more than one return; nested exception is java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
....
Which is weird since calling the query and applying my result set mapping directly by invoking the EntityManage#createNamedQuery method worked perfectly fine.
Am I missing something or should I post this to the Spring Data Jira? Neither JPA's nor Spring's documentation provided information for my case ...
More Background Info:
Actually the additional column anotherField is a transitive property on my Entity. I haven't found a way of mapping that column to the transitive property, which is why my repository method currently returns Object[].

Spring Data JPA: Work with Pageable but with a specific set of fields of the entity

I am working with Spring Data 2.0.6.RELEASE.
I am working about pagination for performance and presentation purposes.
Here about performance I am talking about that if we have a lot of records is better show them through pages
I have the following and works fine:
interface PersonaDataJpaCrudRepository extends PagingAndSortingRepository<Persona, String> {
}
The #Controller works fine with:
#GetMapping(produces=MediaType.TEXT_HTML_VALUE)
public String findAll(Pageable pageable, Model model){
Through Thymeleaf I am able to apply pagination. Therefore until here the goal has been accomplished.
Note: The Persona class is annotated with JPA (#Entity, Id, etc)
Now I am concerned about the following: even when pagination works in Spring Data about the amount the records, what about of the content of each record?.
I mean: let's assume that Persona class contains 20 fields (consider any entity you want for your app), thus for a view based in html where a report only uses 4 fields (id, firstname, lastname, date), thus we have 16 unnecessary fields for each entity in memory
I have tried the following:
interface PersonaDataJpaCrudRepository extends PagingAndSortingRepository<Persona, String> {
#Query("SELECT p.id, id.nombre, id.apellido, id.fecha FROM Persona p")
#Override
Page<Persona> findAll(Pageable pageable);
}
If I do a simple print in the #Controller it fails about the following:
java.lang.ClassCastException:
[Ljava.lang.Object; cannot be cast to com.manuel.jordan.domain.Persona
If I avoid that the view fails with:
Caused by:
org.springframework.expression.spel.SpelEvaluationException:
EL1008E:
Property or field 'id' cannot be found on object of type
'java.lang.Object[]' - maybe not public or not valid?
I have read many posts in SO such as:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to
I understand the answer and I am agree about the Object[] return type because I am working with specific set of fields.
Is mandatory work with the complete set of fields for each entity? Should I simply accept the cost of memory about the 16 fields in this case that never are used? It for each record retrieved?
Is there a solution to work around with a specific set of fields or Object[] with the current API of Spring Data?
Have a look at Spring data Projections. For example, interface-based projections may be used to expose certain attributes through specific getter methods.
Interface:
interface PersonaSubset {
long getId();
String getNombre();
String getApellido();
String getFecha();
}
Repository method:
Page<PersonaSubset> findAll(Pageable pageable);
If you only want to read a specific set of columns you don't need to fetch the whole entity. Create a class containing requested columns - for example:
public class PersonBasicData {
private String firstName;
private String lastName;
public PersonBasicData(String firstName, String lastName) {
this.firstName = fistName;
this.lastName = lastName;
}
// getters and setters if needed
}
Then you can specify query using #Query annotation on repository method using constructor expression like this:
#Query("SELECT NEW some.package.PersonBasicData(p.firstName, p.lastName) FROM Person AS p")
You could also use Criteria API to get it done programatically:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<PersonBasicData> query = cb.createQuery(PersonBasicData.class);
Root<Person> person = query.from(Person.class);
query.multiselect(person.get("firstName"), person.get("lastName"));
List<PersonBasicData> results = entityManager.createQuery(query).getResultList();
Be aware that instance of PersonBasicData being created just for read purposes - you won't be able to make changes to it and persist those back in your database as the class is not marked as entity and thus your JPA provider will not work with it.

Spring data elastic search findAll with OrderBy

I am using spring data's elastic search module, but I am having troubles building a query. It is a very easy query though.
My document looks as follows:
#Document(indexName = "triber-sensor", type = "event")
public class EventDocument implements Event {
#Id
private String id;
#Field(type = FieldType.String)
private EventMode eventMode;
#Field(type = FieldType.String)
private EventSubject eventSubject;
#Field(type = FieldType.String)
private String eventId;
#Field(type = FieldType.Date)
private Date creationDate;
}
And the spring data repository looks like:
public interface EventJpaRepository extends ElasticsearchRepository<EventDocument, String> {
List<EventDocument> findAllOrderByCreationDateDesc(Pageable pageable);
}
So I am trying to get all events ordered by creationDate with the newest event first. However when I run the code I get an exception (also in STS):
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property desc found for type Date! Traversed path: EventDocument.creationDate.
So it seems that it is not picking up the 'OrderBy' part? However a query with a findBy clause (eg findByCreationDateOrderByCreationDateDesc) seems to be okay. Also a findAll without ordering works.
Does this mean that the elastic search module of spring data doesn't allow findAll with ordering?
Try adding By to method name:
findAllByOrderByCreationDateDesc

Unable to access MetaModel entity attributes

I have tried to access the MetaModel entity attributes/variables using the code below:
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Metamodel m = entityManager.getMetamodel();
EntityType<User> User_ = m.entity(User.class);
Root<User> userRoot = criteria.from(User.class);
criteria.where(builder.equal(userRoot.get(User_.email)), user.getEmail());
but email cannot be resolved or is not a field.
Is it mandatory to create StaticMetaModel class for User class. i.e., "User_" ???
If YES, please see the link http://docs.oracle.com/javaee/6/tutorial/doc/gkjbq.html
here, you can find the below code:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido"));
Please help me here.
That Oracle documentation you refer to is utterly wrong. The STATIC metamodel is generated by an annotation processor. It is not obtained via the JPA Metamodel class.
The STATIC (canonical) metamodel class with "_" is not an EntityType object.
See the JPA spec section 6.2.1.1 and documentation such as this one.

Spring Data map results

I use Spring Data and I can't find a way to map a #Query results into a DTO. E.g on the query
#Query("select f.a f.b from Foo f")
List<FooStripped> find();
where
public class FooStripped {
String a;
String b;
...
}
I want all the results to be mapped to a list of FooStripped an Object[] is returned.
You can see an example for this in Is there a way to transform objects that spring data repositories return?
But I would not do that to be honest. I would advice you do to this manually in the service/controller level. You can use for this the following framework http://modelmapper.org/ or any other object mapping framework.