JPA: dealing with Views - java

I'm trying to implement a Repository to work with Views. The fact is that I'm trying to use the SimpleJpaRepository implementation, but I'm getting a lot of errors on execution time because my DTO is not an #Entity. It is only a #Table, and it seems that this kind of elements are not mapped into the Metamodel of JPA.
This is my DTO:
#Table(name = "v_language")
public class VLanguage {
#Column(name = "isocode")
private String isocode;
#Column(name = "name")
private String name;
#Column(name = "isdefault")
private String isdefault;
// getters and setters
...
}
I tried to define a customized base repository with minimal functionality (only a findAll() method) with the same implementation of SimpleJpaRepository, but when building the Query it fails when doing:
Root<U> root = query.from(domainClass);
With this exception:
Caused by: java.lang.IllegalArgumentException: Not an entity: class es.prodevelop.pui.common.jpa.model.views.dto.VLanguage
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:194)
at org.hibernate.jpa.criteria.QueryStructure.from(QueryStructure.java:124)
at org.hibernate.jpa.criteria.CriteriaQueryImpl.from(CriteriaQueryImpl.java:156)
at es.prodevelop.pui.common.jpa.configuration.AbstractRepository.applySpecificationToCriteria(AbstractRepository.java:213)
at es.prodevelop.pui.common.jpa.configuration.AbstractRepository.getQuery(AbstractRepository.java:174)
at es.prodevelop.pui.common.jpa.configuration.AbstractRepository.findAll(AbstractRepository.java:151)
...
Does anybody know how to solve it?

you are missing the #Entity annotation.
please annotate your class and try again.

Related

Hibernate Search - issue indexing embedded / associated objects

I'm having difficulty adding index fields to embedded objects using hibernate search.
I have a simple example whereby a Company can have many CompanyAddress(es) - example of my setup is shown below:
Company.java
#Data
#Entity
#Table(name="COMPANY")
#Indexed
public class Company implements Serializable {
...
#OneToMany(mappedBy="company", fetch=FetchType.LAZY,
cascade=CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
#IndexedEmbedded(depth=1, includePaths={"postalCode"})
private Set<CompanyAddress> address;
...
}
CompanyAddress.java
#Data
#NoArgsConstructor
#Entity
#Table(name="COMPANY_ADDRESS")
#Indexed
public class CompanyAddress implements Serializable {
#ManyToOne
#JoinColumn(name="company_id", referencedColumnName = "id")
#JsonBackReference
#ContainedIn
private Company company;
#Column(name="POSTAL_CODE", length=10)
private String postalCode;
}
When I try to index I get the following error:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH000216: Found invalid #IndexedEmbedded->paths elements configured for member 'address' of class 'com.example.model.Company'. The invalid paths are [address.postalCode]
Now if I swap the #Contained and #IndexedEmbedded to be on the address object I can index and find companies from addresses however I would wish to be able to include address fields in the Company index.
I'm using hibernate search 5.11.11.Final.
Any guidance would be much appreciated.
Ok I solved this - adding an #Field annotation to the postalCode attribute meant the field was indexed and the error didn't occur.
Hopefully this will be useful for anyone else with similar problems.

Crnk JsonApiRelation, OneToMany and filtering implementation

I use crnk (JSON-API) in java project and I have 3 questions regarding its usage with spring boot and jpa - haven't found exact implementation details in documentation.
For example, I have 2 entities and respective tables:
#Entity
#JsonApiResource(type = "employee")
public class Employee {
#Id
#JsonApiId
private int id;
private String name;
#ManyToOne
#JoinColumn(name = "typeId")
private EmployeeType employeeType; //stored in table as typeId
}
#Entity
#JsonApiResource(type = "type")
public class EmployeeType {
#Id
#JsonApiId
private int id;
private String typeName;
private int salary;
}
How should JsonApiRelation be introduced in order to be able to call "/employee/1" and "/employee/1/type" urls?
For example there is one more entity.
#Entity
#JsonApiResource(type = "project")
public class Project {
#Id
#JsonApiId
private int id;
private String supervisorName;
private String projectName;
}
First, I'd like to have List of Projects for each Employee, where he is a supervisor, joint by name and have it listed as attribute in Json.
Tried implementing it with #OneToMany and #JoinColumn annotations but got StackOverflowException. How could this be implemented. And second, how could this be implemented with Relation? Like "/employee/1/projects" url.
How should I implement custom filtering of results for findAll method? For example, I have a List of all Employees, but I'd like to exclude some of them from the response. Which class/method should be introduced for this behaviour?
#JsonApiRelation annotation should not be necessary. Crnk will detect the #ManyToOne annotation and map it accordingly.
in case of crnk-jpa it is sufficient to specify all relationships in JPA. Matching JSON API relationships. So your approach seems good. What was the StackoverflowException stacktrace? (next to the examples, there are also many example entities in crnk-jpa)
I would make use of a decorator. See http://www.crnk.io/documentation/#_request_filtering. RepositoryDecoratorFactory allows to place a custom repository between the caller and crnk-jpa (or any other kind of repository). There you can do any kind of modification perform (maybe) calling the "real" repository. => Will add an example for this
feel free also make open up tickets in crnk for any documentation/example clarifications.

Hibernate ignoring discriminator column - always using 'dtype'

I have a strange situation in my SINGLE_TAB inheritance Hibernate config whereby the #DiscriminatorColumn seems to be ignored and the query is always defaulting back to the 'dtype' column. It's like the behaviour I would see when I had not included the annotation at all (the default column name being 'dtype').
Base entity:
#Entity
#Table(name = "post")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(columnDefinition = "post_type", discriminatorType = DiscriminatorType.STRING)
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "title")
private String title;
#Column(name = "body")
private String body;
#NotNull
#Column(name = "post_type", insertable = false, updatable = false)
private String postType;
// other simple columns
// ommit getters/setters + hashcode etc
}
Subclass entity:
#Entity
#DiscriminatorValue(value = "EVENT")
public class Event extends Post {
// ommitted basic methods, no extra config
}
I also need access to the discriminator value itself within each object (the postType field). I still have the same behaviour even if I remove it so it doesn't seem to be the cause.
When I try to do a query on the subclass through a JPA repository:
public interface EventRepository extends JpaRepository<Event, Integer> {
List<Event> findAll();
}
Hibernate generates the query:
select post0_.id as id2_4_, post0_.bodyl as body_bod3_4_, post0_.title as title12_4_
from post post0_
where post0_.dtype='EVENT'
which of course generates an error as 'dtype' doesn't exist in the table.
The strange thing is that if I use #DiscriminatorFormula("post_type") on the Post entity instead, everything seems to work. It is however slower so I would prefer to use the #DiscriminatorColumn as it should fit my needs exactly.
I am using Hibernate 5.2.10-FINAL and Spring Data JPA 1.11.4 (or generally the latest of hopefully everything).
Any ideas on what could be causing this?
I'm think you have this problem because you specified wrong parameter of #DiscriminatorColumn anotation, you should use name instead of columnDefinition.

Hibernate #Transient MappingException

I am trying to add a Transient property to my Embeddable class. Here is what I have:
#NoArgsConstructor
#AllArgsConstructor
#Data
#Builder
#Embeddable
public class PackageProduct
{
#Field
private String productId;
#Transient
private Product product;
}
And PackageProduct is used in Package.java like this;
#ElementCollection(targetClass=PackageProduct.class, fetch = FetchType.EAGER)
private Set<PackageProduct> packageProducts;
However, this throws the following exception:
Caused by: org.hibernate.MappingException: Could not determine type for: *.*.*.Product, at table: Package_packageProducts, for columns: [org.hibernate.mapping.Column(packageProducts.product)]
The exception is no longer thrown if I annotate my PackageProduct class with this:
#Access(AccessType.FIELD)
I am trying to understand why it works with the class level #Access annotation. Any help is appreciated. Thanks.
In hibernate either you can apply all annotations on fields or methods, simultaneously mix use is not allow.To override this #Access is needed.In your product class if you are using such case, rectify this.

Hibernate - org.hibernate.QueryException: could not resolve property:

I have a class DocMovement like this :
#Entity
#Table(name = "DOC_MVMNT")
public class DocMovement {
#Id
#GeneratedValue
#Column(name = "MVMNT_ID")
private int mvmnt_id;
#ManyToOne
#JoinColumn(name = "BARCODE")
public DocMaster docMaster;
// other fields and getters setters
}
The DocMaster class is something like this :
#Entity
#Table(name="DOC_MASTER")
public class DocMaster {
#Id
#NotNull
#Column(name = "BARCODE")
private String barcode;
#Column(name = "DOC_NO")
private String docNo ;
#Column(name="DOC_TYPE")
private String docType;
#Column(name="STATUS")
private String status;
// other fields and getters setters
}
When I am trying to run following code :
Criteria criteria = session.createCriteria(DocMovement.class,"documentMovement");
criteria.add(Restrictions.eq("documentMovement.recipientDetail.empId", empId));
criteria.add(Restrictions.eq("documentMovement.isCurrent", true));
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.CLOSED_STATUS));
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.DISPOSED_STATUS));
List<DocMovement> documentsHeld = (List<DocMovement>) criteria.list();
then I get the following exception :
[org.hibernate.QueryException: could not resolve property:
docMaster.status of: com.fms.persistence.DocMovement] with root cause
org.hibernate.QueryException: could not resolve property:
docMaster.status of: com.fms.persistence.DocMovement
there are other cases where I try to make query using criteria as shown above, the query runs fine, but I am unable to understand what am I doing wrong in this case. I have tried using eager fetch too, earlier I was not using an alias, so I tried using an alias too.
Please help me solve the issue !!!
Try adding alias :
criteria.createAlias("documentMovement.docMaster", "docMaster")
And later call
criteria.add(Restrictions.ne("docMaster.status",FMSConstants.CLOSED_STATUS));
You have to add an alias to docMaster first
I think that it's the comparaison with the enums that are not correct. You are trying to compare an enum with a String. This line seems wrong:
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.CLOSED_STATUS));
Since documentMovement.docMaster.status is defined as a String, maybe try:
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.CLOSED_STATUS.toString()));
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.DISPOSED_STATUS.toString()));

Categories