What is root path in QueryDSL? Can you explain with an example? - jpa

I have the following two entity classes: Country and Type
#Entity
#Table(name = "countries")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id ;
#Column(name = "iso_code")
private String isoCode;
public Country() {
}
public Country(String isoCode) {
this.isoCode = isoCode;
}
public Country(int id, String isoCode) {
this.id = id;
this.isoCode = isoCode;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getIsoCode() {
return isoCode;
}
public void setIsoCode(String isoCode) {
this.isoCode = isoCode;
}
#Override
public String toString() {
return "Country{" +
"id=" + id +
", isoCode='" + isoCode + '\'' +
'}';
}
}
#Entity
#Table(name = "types")
public class Type {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "type")
private String type;
#ManyToOne
#JoinColumn(name = "country_id")
private Country country;
#ManyToOne
#JoinColumn(name = "group_id")
private Group group;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Group getGroup() {
return group;
}
public void setGroup(int priority) {
this.group = group;
}
}
I am trying to retrieve groups using the following in the repository class:
QType qType = QType.type1;
QCountry qCountry = QCountry.country;
QGroup qGroup = QGroup.group;
QGroup qGroup1 = qType.group;
JPAQuery queryGroup = new JPAQuery(em);
QueryBase queryBaseGroups = queryGroup.from(qGroup).innerJoin(qGroup1, qGroup).innerJoin(qType.country, qCountry);
However, I get the error -
java.lang.IllegalArgumentException: Undeclared path 'type1'. Add this path as a source to the query to be able to reference it.
New to JPA. What am I doing wrong here?

So this was solved by adding qType to the from function in the query.
QueryBase queryBaseGroups = queryGroup.from(qGroup, qType).innerJoin(qGroup1, qGroup).innerJoin(qType.country, qCountry);

Related

Spring Data JPA. Parent table data is not getting rolled back when exception occurred while inserting record in child table

I have 2 tables one to many relationship between Employee and Department table, Employee table are having column Id as PK, Name and Sal whereas Department table having column Dept_ID,Dept_Name & Dept_Loc and primary key is (Dept_ID,Dept_Name) i.e composite key and Dept_ID is foreign key ref from Employee table's Id column. The issue is when I save record in parent table i.e Employee it get saved but if in case I get exception while inserting record for child table i.e Department table,,data is not getting rolled back for EMployee table. Please help I m struggling and I am attaching my code.
public class GlEmployee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_seq")
#Column(name = "EMP_ID")
private long empId;
#Column(name = "EMP_CITY")
private String empCity;
#Column(name = "EMP_NAME")
private String empName;
#Column(name = "EMP_SALARY")
private BigDecimal empSalary;
// bi-directional many-to-one association to EmpDepartment
#OneToMany(mappedBy = "glEmployee",cascade = CascadeType.ALL)
private List<EmpDepartment> empDepartments = new ArrayList<>();
public GlEmployee() {
}
public long getEmpId() {
return this.empId;
}
public void setEmpId(long empId) {
this.empId = empId;
}
public String getEmpCity() {
return this.empCity;
}
public void setEmpCity(String empCity) {
this.empCity = empCity;
}
public String getEmpName() {
return this.empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public BigDecimal getEmpSalary() {
return this.empSalary;
}
public void setEmpSalary(BigDecimal empSalary) {
this.empSalary = empSalary;
}
public List<EmpDepartment> getEmpDepartments() {
return this.empDepartments;
}
public void setEmpDepartments(List<EmpDepartment> empDepartments) {
this.empDepartments = empDepartments;
}
public EmpDepartment addEmpDepartment(EmpDepartment empDepartment) {
getEmpDepartments().add(empDepartment);
empDepartment.setGlEmployee(this);
return empDepartment;
}
public EmpDepartment removeEmpDepartment(EmpDepartment empDepartment) {
getEmpDepartments().remove(empDepartment);
empDepartment.setGlEmployee(null);
return empDepartment;
}
}
#Entity
#Table(name = "EMP_DEPARTMENT")
public class EmpDepartment implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private EmpDepartmentPK id;
#Column(name = "DEP_LOC")
private String depLoc;
public EmpDepartment(EmpDepartment id, String dep) {
}
// bi-directional many-to-one association to GlEmployee
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "DEP_ID", insertable = false, updatable = false)
private GlEmployee glEmployee;
public EmpDepartment() {
}
public EmpDepartmentPK getId() {
return this.id;
}
public void setId(GlEmployee glEmployee, String deptName) {
EmpDepartmentPK empDepartment = new
EmpDepartmentPK(glEmployee.getEmpId(), deptName);
this.id = empDepartment;
}
public String getDepLoc() {
return this.depLoc;
}
public void setDepLoc(String depLoc) {
this.depLoc = depLoc;
}
public GlEmployee getGlEmployee() {
return this.glEmployee;
}
public void setGlEmployee(GlEmployee glEmployee) {
this.glEmployee = glEmployee;
}
}
#Embeddable
public class EmpDepartmentPK implements Serializable {
// default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(name = "DEP_ID")
private long depId;
#Column(name = "DEP_NAME")
private String depName;
public EmpDepartmentPK() {
}
public EmpDepartmentPK(long depId, String depName) {
super();
this.depId = depId;
this.depName = depName;
}
public long getDepId() {
return this.depId;
}
public void setDepId(long depId) {
this.depId = depId;
}
public String getDepName() {
return this.depName;
}
public void setDepName(String depName) {
this.depName = depName;
}
#Service
public class EmployeeService {
#Autowired
private EmployeeRepository employeeRepository;
#Transactional
public void createEmp() {
GlEmployee employee = new GlEmployee();
employee.setEmpCity("Pune");
employee.setEmpName("Ankush");
employee.setEmpSalary(new BigDecimal(200));
employeeRepository.save(employee);
EmpDepartment department = new EmpDepartment();
department.setId(employee, "ME");
department.setDepLoc(null);
department.setGlEmployee(employee);
employee.addEmpDepartment(department);
employeeRepository.save(employee);
}
}

New Entity is created with every Persist JPA

I just get started with JPA. I have an entity CustomerOrderEntity which has #OneToMany relation with another entity BeverageEntity. When I add the BeverageEntity to the CustomerOrderEntity a new entity is created of the type BeverageEntity and is persisted in the database as a new record. I do not want something like that I only need the CustomerOrderEntity to have the record of BeverageEntity and a new entity is not created for that inside the database.
These two entities are invoked from this class SalesManagement:
#Stateless
#Remote(SalesManagement.class)
public class SalesManagementBean implements SalesManagement {
#PersistenceContext(type = PersistenceContextType.TRANSACTION)
EntityManager em;
#Override
public void createOrder(CustomerOrder order) {
order.getOrderItems().forEach(item -> {
updateBeverageQuantity(item.getId(), item.getQuantity());
});
CustomerOrderEntity customerOrderEntity = new CustomerOrderEntity();
customerOrderEntity.setIssueDate(order.getIssueDate());
order.getOrderItems().forEach(item ->{
customerOrderEntity.addOrder(toEntity(item));
});
em.persist(customerOrderEntity);
}
public void updateBeverageQuantity(int b_id, int quantity) {
BeverageEntity beverageEntity = em.find(BeverageEntity.class, b_id);
if(beverageEntity != null) {
beverageEntity.setQuantity(beverageEntity.getQuantity() - quantity);
em.persist(beverageEntity);
}
}
public List<BeverageEntity> toBeverageEntity(List<Beverage> beverages) {
List<BeverageEntity> entities = new ArrayList<BeverageEntity>();
if(beverages != null && beverages.size() > 0) {
beverages.forEach(beverage -> {
BeverageEntity entity = new BeverageEntity();
entity.setName(beverage.getName());
entity.setManufacturer(beverage.getManufacturer());
entity.setQuantity(beverage.getQuantity());
entity.setPrice(beverage.getPrice());
entity.setIncentiveEntity(toIncentiveEntity(beverage.getIncentiveDTO()));
entities.add(entity);
});
return entities;
}
return null;
}
public IncentiveEntity toIncentiveEntity(IncentiveDTO incentiveDTO) {
if(incentiveDTO != null) {
IncentiveEntity entity = null;
return entity;
}
return null;
}
public BeverageEntity toEntity(Beverage b) {
BeverageEntity entity = new BeverageEntity();
entity.setName(b.getName());
entity.setManufacturer(b.getManufacturer());
entity.setQuantity(b.getQuantity());
entity.setPrice(b.getPrice());
entity.setIncentiveEntity(toIncentiveEntity(b.getIncentiveDTO()));
return entity;
}
}
I think the problem is in the method toBeverageEntity. But I am not sure about it.
The CustomerOrderEntity:
#Entity
public class CustomerOrderEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;
#Version
private int version;
private Date issueDate;
#OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
private List<BeverageEntity> beverageEntities;
public void addOrder(BeverageEntity beverageEntity) {
this.beverageEntities.add(beverageEntity);
}
public List<BeverageEntity> getBeverageEntities() {
return beverageEntities;
}
public void setBeverageEntities(List<BeverageEntity> beverageEntities) {
this.beverageEntities = beverageEntities;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getIssueDate() {
return issueDate;
}
public void setIssueDate(Date issueDate) {
this.issueDate = issueDate;
}
}
The BeverageEntity:
#Entity
public class BeverageEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;
private String name;
private String manufacturer;
private int quantity;
private double price;
#Version
private int version;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
private IncentiveEntity incentiveEntity;
public BeverageEntity() {
}
public BeverageEntity(String name, String manufacturer, int quantity, Double price, IncentiveEntity entity) {
this.name = name;
this.manufacturer = manufacturer;
this.quantity = quantity;
this.price = price;
this.incentiveEntity = entity;
}
public BeverageEntity(String name, String manufacturer, int quantity, Double price) {
this.name = name;
this.manufacturer = manufacturer;
this.quantity = quantity;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public IncentiveEntity getIncentiveEntity() {
return incentiveEntity;
}
public void setIncentiveEntity(IncentiveEntity incentiveEntity) {
this.incentiveEntity = incentiveEntity;
}
}
Found the problem it was in the method toBeverageEntity as pointed out in the comments I was creating a new entity that was wrong. I needed to use find because the entity is already in the database.
BeverageEntity entity = em.find(BeverageEntity.class, beverage.getId());
entities.add(entity);

JPA data retreival issue on webshpehre liberty and jax-rs 2.0

Here is my entity class
#Entity
#Table( name = "NEO_TEAM", schema = "METRICS" )
public class ETeam implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID")
private int id;
#Column(name="NAME")
private String name;
#Column(name="DESCRIPTION")
private String description;
//bi-directional many-to-one association to ETeamQueue
#OneToMany(mappedBy="eteam" , fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<ETeamQueue> teamQueue;
public ETeam(int id,String name,String description){
this.id = id;
this.name = name;
this.description = description;
}
public ETeam(String name,String description){
this.name = name;
this.description = description;
}
public ETeam() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public List<ETeamQueue> getTeamQueue() {
return this.teamQueue;
}
public void setTeamQueue(List<ETeamQueue> teamQueue) {
this.teamQueue = teamQueue;
}
public ETeamQueue addTeamQueue(ETeamQueue teamQueue) {
getTeamQueue().add(teamQueue);
teamQueue.setEteam(this);
return teamQueue;
}
public ETeamQueue removeTeamQueue(ETeamQueue teamQueue) {
getTeamQueue().remove(teamQueue);
teamQueue.setEteam(null);
return teamQueue;
}
}
And My REST call and JPQL query is
#Path("team")
#Produces(MediaType.APPLICATION_JSON)
public class TeamResource {
TeamService ts = new TeamService();
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public List<ETeam> listTeam(#PathParam("id") int id){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("NeoMetrics");
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("select e from ETeam e where e.id = :id ",ETeam.class);
query.setParameter("id", id);
List<ETeam> lis = (List<ETeam>) query.getResultList();
//List<ETeam> lis = ts.getTeam(id);
return lis;
}
i want to fetch only one record from the team table but it give me result like shown in picture , which show the result is looped thousand times , its very long output result i only put part of it , any help will be really appreciated

The name of the variable is added to the name of the column

I have two entities - Group and UserGroup, they are connected with groupId.
"\" are because postgre is case sensitive and this way we correct this fact.
#Entity
#Table(name = "\"Group\"")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "\"groupId\"")
private int groupId;
#Column(name = "\"groupName\"")
private String groupName;
#OneToMany(mappedBy = "group")
List<Project> projects;
#OneToMany(mappedBy = "group")
private List<UserGroup> members;
public Group(String groupName) {
this.groupName = groupName;
}
public Group() {
}
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public List<Project> getProjects() {
return projects;
}
public void setProjects(List<Project> projects) {
this.projects = projects;
}
public List<UserGroup> getMembers() {
return members;
}
public void setMembers(List<UserGroup> members) {
this.members = members;
}
#Override
public String toString() {
return "Group{" +
"groupId=" + groupId +
", groupName='" + groupName + '\'' +
'}';
}
}
And UserGroup
#Entity
#Table(name = "\"UserGroup\"")
#IdClass(GroupAssociationId.class)
public class UserGroup {
#Id
#Column(name = "\"userId\"")
private int userId;
#Id
#Column(name = "\"groupId\"")
private int groupId;
#ManyToOne
#PrimaryKeyJoinColumn(name = "\"userId\"", referencedColumnName = "\"userId\"")
private User member;
#ManyToOne
#PrimaryKeyJoinColumn(name = "\"groupId\"", referencedColumnName = "\"groupId\"")
private Group group;
#ManyToOne
#JoinColumn(name = "\"accessId\"")
private Access access;
public UserGroup(Group group, User member, Access access) {
this.group = group;
this.member = member;
this.access = access;
}
public UserGroup() {
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
public User getMember() {
return member;
}
public void setMember(User member) {
this.member = member;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
public Access getAccess() {
return access;
}
public void setAccess(Access access) {
this.access = access;
}
#Override
public String toString() {
return "UserGroup{" +
"userId=" + userId +
", groupId=" + groupId +
", access=" + access.getAccessName() +
'}';
}
}
When I try to create a row in a table UserGroup I get a mistake:
Caused by: org.postgresql.util.PSQLException: ERROR: column "group_groupId" of relation "UserGroup" does not exist
Why? This happens on the string "em.getTransaction().commit(). It is really strange.
In the table UserGroup, a column:
"group_`groupId`"
was generated (because you are using "" to preserve case sensitive.
You can edit in postgres the name for the column (and the foreing key too):
"group_`groupId`" ---> "group_groupId"
JPA is looking for group_groupId.
I've managed to answer this question. The problem was in sequence generation. When generating in embedded database, I don't know why, the generation type sequence doesn't work. Instead I used Identity type and everything started working

Wrong parameter binding when using named queries with optional parameters in EclipseLink

I'm trying to do a database lookup using JPA with EclipseLink. My database is Oracle 11.2.0. I have the following entity classes defined:
#Entity
#Table(name = "BS_PROVIDERS")
public class BsProvider {
#Id
#Column(name = "GUID")
private String guid;
public String getGuid() { return guid; }
public void setGuid(String guid) { this.guid = guid; }
#Column(name = "NAME")
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
#Entity
#Table(name = "CP_PROVIDERS")
public class CpProvider{
#Id
#Column(name = "GUID")
private String guid;
public String getGuid() { return guid; }
public void setGuid(String guid) { this.guid = guid; }
#Column(name = "NAME")
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
#NamedQueries({
#NamedQuery(
name = Catalog.FIND_BY_CPP_AND_BSP,
query = "select c from Catalog c where (c.cpProvider = :cpProvider) and ( (:bsProvider IS NULL) or (c.bsProvider = :bsProvider))"
)
})
#Entity
#Table(name = "CATALOGS")
public class Catalog {
public static final String FIND_BY_CPP_AND_BSP = "Catalog.findByCppAndBsp";
public static final String CP_PROVIDER_PARAM = "cpProvider";
public static final String BS_PROVIDER_PARAM = "bsProvider";
#Id
#Column(name = "GUID")
private String guid;
public String getGuid() { return guid; }
public void setGuid(String guid) { this.guid = guid; }
#Column(name = "NAME")
private String name;
public String getName() { return name; }
public void setName() { this.name = name; }
#ManyToOne
#JoinColumn(name = "CPP_GUID")
private CpProvider cpProvider;
public CpProvider getCpProvider() { return cpProvider; }
public void setCpProvider(CpProvider cpProvider) { this.cpProvider = cpProvider; }
#ManyToOne()
#JoinColumn(name = "BSP_GUIG")
private BsProvider bsProvider;
public BsProvider getBsProvider() { return bsProvider; }
public void setBsProvider(BsProvider bsProvider) { this.bsProvider = bsProvider; }
}
Code that creates the query and sets the parameters:
TypedQuery<Catalog> catalogQuery = em.createNamedQuery(Catalog.FIND_BY_CPP_AND_BSP, Catalog.class);
catalogQuery.setParameter(Catalog.CP_PROVIDER_PARAM, cpProvider);
catalogQuery.setParameter(Catalog.BS_PROVIDER_PARAM, bsProvider);
List<Catalog> catalogList = catalogQuery.getResultList();
When the variable bsProvider is NULL, all parameters are registerd are registerd correctly according to the EclipseLink log:
SELECT GUID, NAME, BSP_GUIG, CPP_GUID FROM CATALOGS WHERE ((CPP_GUID = ?) AND ((? IS NULL) OR (BSP_GUIG = ?)))
bind => [18EC0EDB-21A4-4845-960A-D5D2BDAC7B87, null, null]
Otherwise when the variable bsProvider refers to an existing entity I get the following exception:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Invalid column type
Error Code: 17004
Call: SELECT GUID, NAME, BSP_GUIG, CPP_GUID FROM CATALOGS WHERE ((CPP_GUID = ?) AND ((? IS NULL) OR (BSP_GUIG = ?)))
bind => [18EC0EDB-21A4-4845-960A-D5D2BDAC7B87, com.bssys.ebpp.dbaccess.model.BsProvider#5dbbe8df, 44E8F4BF-CFDC-49DB-AB0B-718C72D6B4EF]
As you can see the first and the third parameters are bound correctly (they are replaced by the primary key values), but the second is not. What's the reason of such a strange behavior?