Hibernate Criteria: How to retrieve table data with foreign key relationship - java

I have two pojo classes wihch are named Document and DocumentUser. DocumentUser has an property documentId which linked to Document's id by foreign key.
So i want to create criteria query which retrieve Documents with its DocumentUser which is linked itself by forein key("document_id")
pojo classes:
Document
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#Entity
#Table(name = "DYS_BYS_DOSYA")
#Audited
public class Document implements Serializable {
private Long id;
private String name;
private List<DocumentUser> documentUserList = new ArrayList<DocumentUser>();
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID", nullable = false, precision = 15, scale = 0)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "AD", nullable = false, length = 500)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "document", fetch = FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#Cascade(CascadeType.ALL)
public List<DocumentUser> getDocumentUserList() {
return documentUserList;
}
public void setDocumentUserList(List<DocumentUser> documentUserList) {
this.documentUserList = documentUserList;
}
#Override
public String toString() {
return "tr.com.enlil.dys.server.servis.model.Document[id=" + id + "]";
}
}
DocumentUser:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#Entity
#Table(name = "DYS_DOSYA_SAHIBI_USER")
#Audited
public class DocumentUser implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6393919788296838129L;
private Long id;
private Long personelId;
private Document document;
private String personelName;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID", unique = true, nullable = false, precision = 15, scale = 0)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "OLUSTURUCU_PERSONEL_ID")
public Long getPersonelId() {
return personelId;
}
public void setPersonelId(Long personelId) {
this.personelId = personelId;
}
#Column(name = "KULLANICI_AD")
public String getPersonelName() {
return personelName;
}
public void setPersonelName(String personelName) {
this.personelName = personelName;
}
#ManyToOne
#JoinColumn(name = "DOSYA_ID")
public Document getDocument() {
return document;
}
public void setDocument(Document document) {
this.document = document;
}
}
In this way, how can i get Document data depends on personelId of DocumentUser table by using criteria query? I am not familiar with hibernate and i need your helps. I try to write some codes but didn't work.
public List<Document> fetchRecordsByCriteriaLimitedList(String userId) throws Exception{
Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(Dosya.class);
DetachedCriteria dosyaSahibiCriteria = (DetachedCriteria) criteria.createCriteria("documentUserList");
dosyaSahibiCriteria.add(Restrictions.eq("personelId", userId));
dosyaSahibiCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return criteria.list();
}

Several problems with your code. First of all, you said
2)DocumentUser is subclass of Document
This isn't true, judging from your code (it would mean that DocumentUser extends Document), but you probably meant they are in a parent -> child relation. Second, in documentUserList mapping, there is this #OneToMany(mappedBy = "dosya", fetch = FetchType.EAGER), which means there is a field named dosya in DocumentUser, and there isn't. Instead, replace it with mappedBy = "document". Assuming everything else is ok, query to get all documents based on their DocumentUser's id would be
public List<Document> fetchRecordsByCriteriaLimitedList(String userId) throws Exception{
Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(Document.class);
criteria.createAlias("documentUserList", "users").add(Restrictions.eq("users.personelId", userId));
return criteria.list();
}

Related

Add Image Column in Broadleaf Admin Custom Entities

I added below mentioned custom entity for insert image from broadleaf admin console. But that image field not appear in the admin console. I added 'MEDIA' filed in my entity class. Please help me to solve this issue.
#Entity
#Table(name="MY_CUSTOM_CLASS")
#Inheritance(strategy = InheritanceType.JOINED)
#AdminPresentationClass(friendlyName = "MyCustomClass")
public class MyCustomClass implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "MyCustomClassId")
#GenericGenerator(
name="MyCustomClassId",
strategy="org.broadleafcommerce.common.persistence.IdOverrideTableGenerator",
parameters = {
#Parameter(name="segment_value", value="MyCustomClass"),
#Parameter(name="entity_name", value="com.community.core.domain.MyCustomClass")
}
)
#Column(name = "MY_CUSTOM_CLASS_ID")
protected Long id;
#Column(name = "NAME", nullable = false)
#AdminPresentation(friendlyName = "MyCustomClass_name", order = 1,
prominent = true, gridOrder = 1)
protected String name;
#ManyToOne(targetEntity = MediaImpl.class, cascade = {CascadeType.ALL})
#JoinColumn(name = "MEDIA_ID")
#ClonePolicy
protected Media media;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Media getMedia() {
return media;
}
public void setMedia(Media media) {
this.media = media;
}
}
Any help or workarounds are really appricated.
Put an #AdminPresentation annotation on the media field.

Save an entity and all its related entities in a single save in spring boot

I'm using Spring Boot,REST and JPA to build my application. In app, there are 2 entities with one to many relationship.
Entity 1 :
#Entity
#Table( name = "report")
#JsonIgnoreProperties(ignoreUnknown = true)
public class CustomReport {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REPORT_SEQ")
#SequenceGenerator(sequenceName = "REPORT_SEQ", allocationSize = 1, name = "REPORT_SEQ")
private Long id;
private String name;
private Long createdBy;
private Timestamp lastModifiedTimestamp;
#OneToMany(mappedBy = "customReport", cascade = CascadeType.ALL)
private Set<CustomReportActivity> customReportActivitySet;
public Set<CustomReportActivity> getCustomReportActivitySet() {
return customReportActivitySet;
}
public void setCustomReportActivitySet(Set<CustomReportActivity> customReportActivitySet) {
this.customReportActivitySet = customReportActivitySet;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public Timestamp getLastModifiedTimestamp() {
return lastModifiedTimestamp;
}
public void setLastModifiedTimestamp(Timestamp lastModifiedTimestamp) {
this.lastModifiedTimestamp = lastModifiedTimestamp;
}
}
Entity 2:
#Entity
#Table( name = "report_activity")
public class CustomReportActivity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REPORT_ACTIVITY_SEQ")
#SequenceGenerator(sequenceName = "REPORT_ACTIVITY_SEQ", allocationSize = 1, name = "REPORT_ACTIVITY_SEQ")
private Long id;
String activityName;
#ManyToOne
#JoinColumn( name="report_id" )
#JsonBackReference
private CustomReport customReport;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getActivityName() {
return activityName;
}
public void setActivityName(String activityName) {
this.activityName = activityName;
}
public CustomReport getCustomReport() {
return customReport;
}
public void setCustomReport(CustomReport customReport) {
this.customReport = customReport;
}
}
And my request JSON is as follows :
{
"name": "test report",
"createdBy" : 129,
"customReportActivitySet": [
{"activityName":"a"},
{"activityName":"b"},
{"activityName":"c"},
{"activityName":"d"},
{"activityName":"e"}
]
}
I want to save both entities in one shot. I've implemented the save functionality in following way:
#RequestMapping(value="/save", method = RequestMethod.POST)
public ResponseEntity<?> addReport(#RequestBody CustomReport customReport) {
return new ResponseEntity<>(customReportService.createCustomReport(customReport), HttpStatus.CREATED);
}
CustomReportService method:
public CustomReport createCustomReport(CustomReport customReport) {
return customReportRepository.save(customReport);
}
CustomRepository:
public interface CustomReportRepository extends CrudRepository<CustomReport, Long> {
}
But I'm getting the constraint violation exception with this:
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot
insert NULL into ("REPORT_ACTIVITY"."REPORT_ID")
Is it possible to save both entities in one save operation?
Please help!
You would have to add a small piece of code which would populate each CustomReportActivity within the CustomReport instance. Only then the persistence provide can successfully perform the cascade save operation:
public CustomReport createCustomReport(CustomReport customReport) {
customReport.getCustomReportActivitySet.forEach((activity) -> {
activity.setCustomReport(customReport);
});
return customReportRepository.save(customReport);
}
The bottom line is that the dependencies have to be set on both sides of the relationship.
Try this sample, in my case it worked as expected, child entities are saved automatically in a single save operation with creating relations to the parent entity:
#Entity
public class Parent {
#Id
private Long id;
#JoinColumn(name = "parentId")
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Child> children;
}
#Entity
public class Child {
#Id
private Long id;
private Long parentId;
}

How to write #OrderBy annotation for the outer joined table field to sort collection using SQL

There are 3 tables. There is the variable of "relatedCameraSet" need to order by "camera.name" using SQL, but the field of "camera.name" is not in table of "RelatedCamera", is in the outer joined table of "Camera". The following annotation of #OrderBy doesn't work.
#Entity
#Table(name = "MICRO_MAP")
public class MicroMap { //main table
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "NAME", length = 32, nullable = false)
private String name;
#OneToMany(mappedBy="mapId",cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#OrderBy("camera.name") //OrderBy the field of "name" in Camera table
private Set<RelatedCamera> relatedCameraSet;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<RelatedCamera> getRelatedCameraSet() {
return relatedCameraSet;
}
public void setRelatedCameraSet(Set<RelatedCamera> relatedCameraSet) {
this.relatedCameraSet = relatedCameraSet;
}
}
#Entity
#Table(name = "RELATED_CAMERA")
public class RelatedCamera {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "MAP_ID")
private String mapId;
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name = "CAMERA_ID", referencedColumnName="id",nullable = true)
private Camera camera;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMapId() {
return mapId;
}
public void setMapId(String mapId) {
this.mapId = mapId;
}
public Camera getCamera() {
return camera;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
}
#Entity
#Table(name = "CAMERA")
public class Camera {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
How to write #OrderBy annotation in order to sort collection by camera name using SQL?
Thanks alot!
I researched your problem and found that from the API docs:
Hibernate JPA 2.1 API
The property or field name must correspond to that of a persistent property or field of the associated class or embedded class within it.
that's why it is not possible do it by just OrderBy, you can order only by camera_id column from MicroMap class.
What you want can be done by #Sort and implementing Comparable interface or by specifying a Comparator:
Annotation Type Sort
Now i realize it's impossible to do by #OrderBy, and i think it's not efficient to to do by implementing Comparable interface or specifying a Comparator, because it will take two steps to get job done, the step one is query from DB, the step two is sorting in memory. It's efficient to get sorted collection just by SQL.
In order to get high efficiency, i have to change the class of MicroMap as following:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "MICRO_MAP")
public class MicroMap {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "NAME", length = 32, nullable = false)
private String name;
// #OneToMany(mappedBy="mapId",cascade=CascadeType.ALL, fetch=FetchType.EAGER)
// #OrderBy("camera.name") //OrderBy the field of "name" in Camera table, But JPA doesn't support
// private Set<RelatedCamera> relatedCameraSet;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and add a method in DAO or Service class.
public List<RelatedCamera> getRelatedCamera(Long mapId) {
Session session = sessionFactory.getCurrentSession();
List<RelatedCamera> list = session.createQuery(" from RelatedCamera where mapId="+mapId+" order by camera.name").list();
return list;
}

Error :- org.hibernate.PropertyAccessException: could not get a field value by reflection getter

I have Class Customer ,User , Customer has property manager of user class
Class Customer {
/** The manager. */
#ManyToOne(optional = false, cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE})
#JoinColumn(name = "MANAGER")
#JsonSerialize(using = EntitySerializer.class)
#JsonDeserialize(using = UserDeserializer.class)
private User manager;
}
-------------------------------------
Class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = User.TABLE_NAME + "_SEQUENCE")
#SequenceGenerator(name = User.TABLE_NAME + "_SEQUENCE", sequenceName = User.TABLE_NAME + "_SEQ")
#Column(name = FIELD_ID, nullable = false)
#SuppressWarnings("PMD.ShortVariable")
private Integer id;
#Override
public Integer getId() {
return id;
}
#Override
public void setId(final Integer newId) {
//System.out.println("setID");
id = newId;
}
}
Now when i am trying to create criteria
final Criteria criteria = getSession().createCriteria(Customer.class);
criteria.add(Restrictions.ilike("manager", "%"+searchTerm+"%"))
It throwing Error :-
org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.User.id
Caused by:
java.lang.IllegalArgumentException: Can not set java.lang.Integer field com.User.id to java.lang.String
**Id field is integer **
Could you please change the following:
final Criteria criteria = getSession().createCriteria(Customer.class); criteria.add(Restrictions.ilike("manager", "%"+searchTerm+"%"))
by the following:
final Criteria criteria = getSession().createCriteria(Customer.class); criteria.add(Restrictions.ilike("manager.name", "%"+searchTerm+"%"))
LIKE clause is applicable to text column only.
this code to used
return this.sessionFactory.getCurrentSession()
.createCriteria(UserTraining.class)
.add(Restrictions.eq("userProfile.userId", userId))
.list();
You used this annotation to error remove
#Table(name="user_training")
#Entity
public class UserTraining {
#Id
#GeneratedValue
#Column(name="id")
private int id;
//Generate getter setter of id
/*
#Column(name="user_id")
private int userId;
*/
#JsonIgnore
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "user_id")
private UserProfile userProfile;
public UserProfile getUserProfile() {
return userProfile;
}
public void setUserProfile(UserProfile userProfile) {
this.userProfile = userProfile;
}
#OneToOne
#JoinColumn(name = "training_id")
private Training training;
#Column(name="view_count")
private int viewCount;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Training getTraining() {
return training;
}
public void setTraining(Training training) {
this.training = training;
}
public int getViewCount() {
return viewCount;
}
public void setViewCount(int viewCount) {
this.viewCount = viewCount;
}
}

Hibernate Envers - Audited Entity can't recover ID from empty audited table relation

I need some help on Hibernate Envers. I have the following scenario:
I have a Entity in Hibernate/JPA and this Entity has a normal configuration:
package com.algar.fsw.siscos.model;
/**
* TbUsuario generated by hbm2java
*/
#Entity
#Table(name = "SCCTB023_USUARIO")
#Audited
#AuditTable("SCCTB047_USUARIO_ADTRA")
public class Usuario implements java.io.Serializable {
#Id
#Column(name = "NU_USUARIO", nullable = false, scale = 0)
#NotNull
private Long id;
#Column(name = "NO_USUARIO", nullable = false, length = 50)
#NotNull
#Length(max = 50)
private String nome;
#Column(name = "NO_LOGIN", unique = true, nullable = false, length = 16)
#NotNull
#Length(max = 16)
private String login;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "NU_PERFIL", nullable = false)
private Perfil perfil = new Perfil();
#OneToMany(fetch = FetchType.LAZY, mappedBy = "usuario" , cascade = CascadeType.ALL)
private List<UsuarioGrupo> usuariosGrupos = new ArrayList<UsuarioGrupo>();
public Usuario() {
}
public Usuario(Long id ) {
this.id = id;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public Perfil getPerfil() {
return perfil;
}
public void setPerfil(Perfil perfil) {
this.perfil = perfil;
}
public List<UsuarioGrupo> getUsuariosGrupos() {
return usuariosGrupos;
}
public void setUsuariosGrupos(List<UsuarioGrupo> usuariosGrupos) {
this.usuariosGrupos = usuariosGrupos;
}
}
And, this Entity has a relation with this Entity:
package com.algar.fsw.siscos.model;
#Entity
#Table(name = "SCCTB018_PERFIL")
#Audited
#AuditTable("SCCTB042_PERFIL_ADTRA")
public class Perfil implements java.io.Serializable {
#Id
#Column(name = "NU_PERFIL", nullable = false, scale = 0)
#NotNull
private Long id;
#Column(name = "NO_PERFIL", nullable = false, length = 30)
#NotNull
#Enumerated(EnumType.STRING)
private PerfilEnum perfilEnum;
#Column(name = "IC_ATIVO", nullable = false, precision = 1, scale = 0)
private boolean ativo = true;
#Column(name = "NU_NIVEL", nullable = false, precision = 1, scale = 0)
private Long nivel;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return perfilEnum.toString();
}
public boolean isAtivo() {
return ativo;
}
public void setAtivo(boolean ativo) {
this.ativo = ativo;
}
public Long getNivel() {
return nivel;
}
public void setNivel(Long nivel) {
this.nivel = nivel;
}
public PerfilEnum getPerfilEnum() {
return perfilEnum;
}
public void setPerfilEnum(PerfilEnum perfilEnum) {
this.perfilEnum = perfilEnum;
}
}
When I retrieve the Usuario information, everything is ok, but when I call the method getPerfil I receive a NoEntityFoundException because of the ID of the relation. The data exists only in the regular table, in the audited table the data does not exist because the Audited tables were created after the data already exists in the original table so no records were putted on audited table . I need to recover only the ID, I don't need the data from Perfil. So, if I call getPerfil, the only thing I need is the ID information.
Does anyone know a workaround or some solution for this kind of problem?
The reason I need this is because of an WEB application that has a screen that shows the changes in some Entity, showing the values: date_created, property_changed, value_before and value_after. So I'm constructing the logic to compare the revisions manually in java.
Please, could anyone help me?
Thanks
You will need to make a native sql query on the table and pull the id. You'll want to pull the revision id initially (to make the query), and then re-request the data (to get the requisite id using a native query).
If you had data before starting to use Envers, you should create an initial "0" revision containing all that data.
I had similar issue and the only solution (workaround) that helped me was to manual insert all data prior to envers as initial revision 1 with zero timestamp (1970-01-01). For your case it would be something like this:
INSERT INTO REVINFO(REV, REVTSTMP) VALUES(1, 0);
INSERT INTO SCCTB047_USUARIO_ADTRA
(REV, REVTYPE, NU_USUARIO, NO_USUARIO, NO_LOGIN, NU_PERFIL)
SELECT 1, 0, NU_USUARIO, NO_USUARIO, NO_LOGIN, NU_PERFIL FROM SCCTB023_USUARIO;
INSERT INTO SCCTB042_PERFIL_ADTRA
(REV, REVTYPE, NU_PERFIL, NO_PERFIL, IC_ATIVO, NU_NIVEL)
SELECT 1, 0, NU_PERFIL, NO_PERFIL, IC_ATIVO, NU_NIVEL FROM SCCTB018_PERFIL;

Categories