Query multi tables' columns with join in spring data jpa - java

Description:
I have two tables, Shop_Employee and Shop_Employee_Type. I wanna display typeName directly when show the employee detail information, but I don't want to config the relationship(OneToMany or ManyToOne) between this two entity. Because this will load all Shop_Employee_Type column's value, but these values are useless for me, I just need typeName of Shop_Employee_Type.
Below is my code, but it doesn't work.
ShopEmployeeType:
#Entity
#Data
//#DynamicUpdate
public class ShopEmployeeType {
#Id
private String typeId;
private String shopId;
private String typeName;
private Integer typeStatus;
private String typeDescription;
}
Shop_Employee:
#Entity
#Data
public class ShopEmployee {
#Id
private String employeeId;
private String shopId;
private String typeId;
private String name;
private String code;
private String phone;
private Integer status;
private String idcardNumber;
private String image;
//#Transient
private String typeName;
public ShopEmployee() {
}
}
Repository:
#Query(value = "select u.*,t.type_name from shop_employee u inner join shop_employee_type t on u.type_id=t.type_id", nativeQuery = true)
List<ShopEmployee> findAllData();
This could show typeName as I wished, but there is an error appears when I save a new entity Shop_Employee; If I add a #Transient for 'typeName', It could save successfully, but the value of 'typeName' is null when I query entity Shop_Employee.

Your query should return two Objects Shop_Employee and a String, so the return results should not be List<ShopEmployee> it should be :
#Query(value = "select u.*, t.type_name from shop_employee ...", nativeQuery = true)
List<Object[]> findAllData();
Then you can get the ShopEmployee using :
List<Object[]> list = findAllData();
for(Object[] obj : list){
ShopEmployee shopEmployee = (ShopEmployee) obj[0];
String type_name = (String) obj[1];
}
So, in ShopEmployee entity you don't need to use :
//#Transient
//private String typeName;

Related

How to get non related entity using JPA

I have two entities
#Entity
public class Language {
#Id
#GeneratedValue
private int id;
private String name;
private String isoCode;
}
and the another entity
#Entity
public class MainEntity {
#Id
#GeneratedValue
private int id;
private String anotherField;
private Language language; //(here I want to return the full entity)
}
The entities don't have a database relation just a string field, Now I want to do a query for MainEntity but I want to get the full entity
For example
Language
value
id
1
name
English
isoCode
EN
MainEntity
value
id
a
name
xyz
language
EN
I have that repository
public interface MainRepository extends JpaRepository<MainEntity, Integer>{
User findAll();
}
but I want that when I do a search on my primary entity it brings me the entire language entity
for example
MyEntity.Language.getName()
Use native query to read JPA objects? See this simplified example where you can use any valid native sql query syntax.
You could put Language getLanguage() function to MainEntity class.
String sql = "Select * From MyEntityTable Where id between (?1 and ?2)";
Query query = entityMgr.createNativeQuery(sql, MyEntity.class);
query.setParameter(1, 1001);
query.setParameter(2, 2002);
List<MyEntity> list = query.getResultList();
If you don't want to make a reletion between MainEntity and Language you have to make a native query. (As is you can't make also a jpql query because you should have at least the String language in the MainEntity in order to make a join on String isoCode in Language but as I understand I think you don't want to do that).
So you have to perform a native query returning an interface as stated here
public interface IntermediateObject {
int getId();
String getName();
int getLanguageId();
String getLanguageName();
String getIsoCode();
}
In the repository:
#Query("select m.id as id, m.name as name, l.id as languageId, l.name as languageName, l.isoCode as isoCode MainEntity m join Language l on m.language = l.isoCode", native=true)
List<IntermediateObject> someMethod();
In the MainEntity or better another dto you have to declare a constructor:
public class AnotherDto {
private int id;
private String name;
private LanguageDto language;
public AnotherDto(int id, String name, int languageId, String languageName, String isoCOde) {
this.id = id;
this.name = name;
this.language = new LanguageDto(languageId, languageName, isoCode);
}
}
public class LanguageDto {
private int id;
private String name;
private String isoCode;
public LanguageDto(int id, String name, String isoCode) {
this.id;
this.name = name;
this.isoCode = isoCode;
}
}
And in the service layer you have to construct AnotherDto from IntermediateObject
public List<AnotherDto> someMethod() {
return repository.someMethod().stream().map(i -> new AnotherDto(i.getId(), i.getName(), i.getLanguageId(), i.getLanguageName(), i.getIsoCode())).collect(Collectors.toList());
}
and now you have the language object populated.
Anyway I suggest to map the entities instead to do all of this.

Map values returned from Hibernate Native Query to a model

I am quite new to Hibernate. I am using it along-with my Spring Boot project. I want to write native SQL Queries due to the complex joins involved.
On execution of the queries the values returned is in the form of a list and there is no simple way to map them to a HashMap.
Right now I am using the below approach which works but is heavily dependent on the sequence of the values returned from the query list.
Is there any simple and efficient way to map this result.
DAO
#Transactional
public List<Object> getAllUsers() {
Session currentSession = entityManager.unwrap(Session.class);
String queryString = "select ts.id as id, ts.remarks, concat(s.first_name, ' ',s.last_name) as studentName,\n" +
"ts.start_date as startDate, ts.end_date as endDate, ts.status,\n" +
"ts.created_at as createdAt, ts.created_by as createdBy, \n" +
"ts.updated_at as updatedAt, ts.updated_by as updatedBy\n" +
"from TRN_STATUS ts join types lt on ts.type_id = lt.id join users s on s.id = ts.id \n" +
"join category ct on ts.cat_id = ct.id\n" +
"where ts.tenant_id = 1";
NativeQuery query = currentSession.createNativeQuery(queryString);
List<Object> result = (List<Object>) query.getResultList();
currentSession.close();
return result;
}
Service
public List<Map<String, Object>> getCount(Optional<String> userId, String userType, String limit, String offset) {
List<Object> users= userDAO. getAllUsers();
List<Map<String, Object>> userList = new ArrayList<>();
Iterator userItr = users.iterator();
ObjectMapper userMapper = new ObjectMapper();
Map<String, Object> map;
UserModel obj = new UserModel();
while(userItr.hasNext()) {
Object[] resobj = (Object[]) leaveItr.next();
obj.setId(String.valueOf(resobj[0]));
obj.setStartDate(String.valueOf(resobj[1]));
obj.setEndDate(String.valueOf(resobj[2]));
obj.setDescription(String.valueOf(resobj[3]));
obj.setLeaveType(String.valueOf(resobj[4]));
obj.setCategoryId(String.valueOf(resobj[5]));
obj.setCategoryName(String.valueOf(resobj[6]));
obj.setStatus(String.valueOf(resobj[7]));
obj.setDesignation(String.valueOf(resobj[8]));
obj.setActionBy(String.valueOf(resobj[9]));
obj.setStudentName(String.valueOf(resobj[10]));
obj.setImgUrl(String.valueOf(resobj[11]));
map = userMapper.convertValue(obj, Map.class);
userList.add(map);
logger.info("Value displayed was: "+ map);
}
return userList;
}
UserModel
import lombok.Data;
public #Data class UserModel {
private String id;
private String startDate;
private String endDate;
private String description;
private String leaveType;
private String categoryId;
private String categoryName;
private String status;
private String designation;
private String actionBy;
private String studentName;
private String imgUrl;
private String createdDate;
private String hostelName;
private String blockName;
private String roomName;
}
There is way simple and efficient way to map this result
Instead of creating a method and then mapping the required returned value to a bean class, Just create a Entity class that contains all the fields mapped with the fields which are returned in the query .
Use #NamedNativeQuery for providing the query and #SqlResultSetMapping for mapping the fields which are to be returned after executing the query.
For example
#NamedNativeQuery(
name = "getTenders",
query = "SELECT t.id, t.created_at, CONCAT(u.first_name, ' ' , u.last_name) as created_by, t.modified_at, CONCAT(u2.first_name, ' ' , u2.last_name) as modified_by, t.tenders_abbreviation, t.tenders_full_name FROM abc.tenders v\n" +
"LEFT JOIN abc.users u on u.id = v.created_by LEFT JOIN rbac.users u2 on u2.id = v.modified_by",
resultSetMapping = "tendersMappings"
)
#SqlResultSetMapping(name = "tendersMappings", entities = {
#EntityResult(entityClass = TendersEntity.class, fields = {
#FieldResult(name = "id", column = "id"),
#FieldResult(name = "created_at", column = "created_at"),
#FieldResult(name = "modified_at", column = "modified_at"),
#FieldResult(name = "tenders_abbreviation", column = "tenders_abbreviation"),
#FieldResult(name = "tenders_full_name", column = "tenders_full_name"),
#FieldResult(name = "created_by", column = "created_by"),
#FieldResult(name = "modified_by", column = "modified_by")
})
})
#Entity
#Table(name = "tenders", schema = "abc")
public class TendersEntity {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
#Column(name = "created_at")
private String created_at;
#Column(name = "created_by")
private String created_by;
#Column(name = "modified_at")
private String modified_at;
#Column(name = "modified_by")
private String modified_by;
#Column(name = "tenders_abbreviation")
private String tenders_abbreviation;
#Column(name = "tenders_full_name")
private String tenders_full_name;
public TendersEntity() {}
// setters and getters
}
//DAO class
#Repository
#Transactional
public class TendersDaoImpl implements TendersDao {
#Autowired
EntityManager manager;
#Override
public List<TendersEntity> getVendors() {
List<TendersEntity> dataList = new ArrayList<>();
Query query = manager.createNamedQuery("getTenders");
try {
dataList.addAll(query.getResultList());
} catch (Exception ex) {
…….// exception code
}
return dataList;
}
}
You can use SQL Transformers for this:
With native sql returning non-entity beans or Map's is often more useful instead of basic Object[]. With result transformers that is possible.
Example:
List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.addScalar("studentName")
.addScalar("courseDescription")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();
StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);
Reference:
https://docs.jboss.org/hibernate/core/3.3/reference/en/html/querysql.html#d0e13904

Ljava.lang.Object; cannot be cast when getting multipile fields Hibernate Repository

I fresh on spring technology and hibernate. Some days ago i create query getting all rows from table using repository. Today i was try get 2 fields from database. When i try read data form result list i getting Ljava.lang.Object; cannot be cast. This is my enity
#Entity
#Table(name = "cms")
public class Cms implements Serializable{
private static final long serialVersionUID = 1759832392332242809L;
#Id
#GeneratedValue
private Long id_page;
#Column(nullable = false)
private String title;
private String content;
#Temporal(TemporalType.DATE)
private Date createDate;
#Temporal(TemporalType.DATE)
private Date modifyDate;
#Column(nullable = true)
private int createBy;
#Column(nullable = true)
private int modifedBy;
#Column(nullable = false)
private Boolean inMenu;
public Cms(Long id_page, String title, String content, Date createDate,
Date modifyDate) {
this.id_page = id_page;
this.title = title;
this.content = content;
this.createDate = createDate;
this.modifyDate = modifyDate;
this.createBy = 1;
this.modifedBy = 1;
this.inMenu = true;
}
//getters setters to string
}
Repository
public interface CmsRepository extends Repository<Cms, Long>{
#Query("Select u.id_page,u.title from Cms u")
List<Cms> getMenu();
}
And takie this on controller
List<Cms> menus= cmsservice.menuAll();
System.out.println(menus.get(0).toString()); //error
Some one can explain me on example what is bad and how can fix this, this will helpfull for me.
Thats because you are retrieving individual properties - not the entire Cms Object.
I would use an instance of Query for this:
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("Select u.id_page,u.title from Cms u");
List<Object[]> results = query.getResultList();
for(Object[] elements: results){
Long id = Long.valueOf(String.valueOf(elements[0]));
String title = String.valueOf(elements[1]);
}
SELECT NEW org.agoncal.javaee7.CustomerDTO(c.firstName, c.lastName, c.address.
street1)
FROM Customer c

Create new object from two tables JDO DataNucleus

I am attempting to create a DTO object by persisting two classes using DataNucleus.
The DTO I wish to create:
#PersistenceAware
DtoObject{
Protected String Id; //populated by Order class
Protected String status; //populated by Order class
Protected String phoneNumber; //populated by Customer class
Protected String address; //populated by Customer class
}
The Objects:
#PersistenceCapable
#FetchGroup(name="dto", members = {#Persistent(name = "Id"),
#Persistent(name="status")})
public Class Order{
#PrimaryKey
#Persistent
private String Id;
#Persistent
private String status;
#Persistent
private Customer customer;
}
#PersistenceCapable
#FechGroup(name="dto", members = { #Persistent(name = "phoneNumber"),
#Peristent(name="address") })
public Class Customer{
#PrimaryKey
#Persistent
private String Id;
#Persistent
private String phoneNumber;
#Persistent
private string Address;
}
The JDODL:
Query q = pm.newQuery(Order.class);
pm.getFetchPlan().setGroup("dto");
q.setUnique(true);
q.setFilter("Id == id");
q.declareParameters("String id");
q.setResultClass(DtoObject.class);
DtoObject dto = (DtoObject)q.execute(id);
I can populate the dto object with its attributes mapped to the Order.class but can not get the attributes from the Customer.class. Data Nucleus joins the tables and selects the proper columns from each table but leaves the phoneNumber =null and address = null;
Pointers on how to make this work with one query will be appreciated.
Query q = pm.newQuery("SELECT UNIQUE this.id, this.status, " +
" this.customer.phoneNumber, this.customer.address INTO " +
DtoObject.class.getName() +
" FROM " + Order.class.getName() + " WHERE this.id = :id");
DtoObject dto = (DtoObject)q.execute(idParam);
Assuming the result class (DtoObject) obeys the conditions of a result class

org.hibernate.ObjectNotFoundException issue with using list()

The following query throws the exception:
Query query = session.createQuery("from Associate as a order by a.username asc");
associates = query.list();
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [ca.mypkg.model.Associate#0]
If I create an entry in the database with id of 0 it works just fine. I don't really get it because I'm just trying to load all the entries in the db not just a specific one.
Similar questions I've found have been concerned with trying to load an object with a given ID I'm doing no such thing.
Associate class:
#Table(name = "user")
#XmlRootElement(name = "associate")
public class Associate implements Serializable {
private String username;
private String password;
private String firstName;
private String lastName;
private String userType;
private int id;
private String email;
private String isActive;
private Department dept;
private String lastUpdated;
private String associate_type;
// ...
#Id
#GeneratedValue
public int getId() {
return id;
}
#OneToOne
#JoinColumn(name = "dept")
public Department getDept() {
return dept;
}
From my experience this type of error message usually means it does not find joined entity by mentioned id, and not the entity requested in the query (Associate, in your case).
My guess is that Associate class contains a join entity which has primitive type primary key.

Categories

Resources