Associated entity with OneToOne mapping coming in as null - Hibernate - java

I have two entities: TableA and TableB. When I fetch TableA, TableB is always null. What am I doing wrong?
This is how I am getting it:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<TableA> criteriaQuery = builder.createQuery(TableA.class);
Root<TableA> from = criteriaQuery.from(TableA.class);
criteriaQuery.select(from);
This is the Query made:
select generatedAlias0 from TableA as generatedAlias0
TableA:
#Entity
#Table(name = "TableA")
public class TableA implements Serializable {
#Id
#Column(name = "id", nullable = false)
private Integer id = null;
#Id
#Column(name = "active", nullable = false)
private Integer active = null;
private Integer parentId = null;
private String myColA = null;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "id", referencedColumnName = "parentId"),
#JoinColumn(name = "active", referencedColumnName = "active")}
)
#Where(clause = "active=1")
private TableB TableB = null;
private Boolean ignorePlanCutoff = null;
}
TableB:
#Entity
#Table(name = "TableB")
public class TableB implements Serializable {
#Id
#Column(name = "id", nullable = false)
private Integer id = null;
#Id
#Column(name = "active", nullable = false)
private Integer active = null;
private Integer parentId = null;
private Boolean colB = null;
}
Both these entities have composite IDs, not showing that here for brevity.

Related

Hibernate One-to-One, When inserting, Why FK is null

When I run this code, it is running with out error. But When I check the values, as you can see, In the "Tbl_InstructorDetail" table the parentId is null
can anyone help.
thank you.
This is my Entities and my main class with table relation
enter image description here
this is my tables from my database
create table Tbl_Instructor
(
uuid int identity
constraint Pk_Tbl_Instructor_uuid
primary key,
Title nvarchar(50)
)
create table Tbl_InstructorDetail
(
uuid int identity
constraint Pk_Tbl_InstructorDetail_uuid
primary key,
Created_By nvarchar(50),
parentId int
constraint Fk_Tbl_InstructorDetail_Tbl_Instructor
references Tbl_Instructor
)
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
#Basic
#Column(name = "parentId", nullable = true,insertable = false,updatable = false)
private Integer parentId;
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
Main class
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
instructor.setDetailEntity(detail);
session.getTransaction().begin();
session.save(instructor);
session.getTransaction().commit();
You don't need to add parentId in TblInstructorDetailEntity because it's referenced from TblInstructorEntity. In main class foreign key pass null because you can take a reference to the parent table before save parent table.
Here down is modified code:
Entity
#Entity
#Table(name = "Tbl_InstructorDetail", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorDetailEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Created_By", nullable = true, length = 50)
private String createdBy;
// remove parentId column because it is foreign key
#OneToOne
#JoinColumn(name = "parentId",referencedColumnName="uuid")
private TblInstructorEntity instructorEntity;
// getter setter
}
#Entity
#Table(name = "Tbl_Instructor", schema = "dbo", catalog = "OJT_2021_KST")
public class TblInstructorEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "uuid", nullable = false)
private int uuid;
#Basic
#Column(name = "Title", nullable = true, length = 50)
private String title;
#OneToOne(mappedBy="instructorEntity",cascade = CascadeType.ALL)
private TblInstructorDetailEntity detailEntity;
// getter setter
}
Main
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
TblInstructorEntity instructor = new TblInstructorEntity();
instructor.setTitle("This is a Test");
TblInstructorDetailEntity detail = new TblInstructorDetailEntity();
detail.setCreatedBy("Kyle");
session.save(instructor); // Save parent entity
detail.setInstructorEntity(instructor); // Reference from parent entity
session.save(detail); // Save child entity
session.getTransaction().commit();
HibernateUtil.shutdown();

How to write a spring boot jpa specification joining multiple tables

I want to write below query using spring boot specification.
SELECT o.*
from orders as o
inner join user as u on o.user_id = u.id
inner join user_group as ug on u.user_group_id = ug.id
left join order_product op on o.id = op.order_id
left join mobile_order_product mop on op.id = mop.order_product_id
left join mobile_device as md on mop.mobile_device_id = md.id
left join tablet_order_product top on op.id = top.order_product_id
left join tablet_device as td on top.tablet_device_id = td.id
where ug.id = 1
and (md.imei = 123456789 or td.imei = 123456789)
I try to write specification like below but I couldn't find a way to join order_product table.
public static Specification<Order> filterOrdersByGroupIdAndImei(int userGroupId, int imei) {
return (root, query, cb) -> {
Join<Object, User> user = root.join("user");
Join<Object, UserGroup> userGroup = user.join("userGroup");
// how to join order_product and other join tables
Predicate equalPredicate = cb.equal(userGroup.get("id"), userGroupId);
return cb.and(equalPredicate);
};
}
I am going to put answer in my own question.
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(referencedColumnName = "id", nullable = false)
#JsonIgnore
private User user;
#OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
private List<OrderProduct> orderProducts ;
}
#Entity
#Table(name = "order_product")
public class OrderProduct {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(referencedColumnName = "id", nullable = false)
#JsonIgnore
private Order order;
#OneToMany(mappedBy = "orderProduct", fetch = FetchType.LAZY)
private List<MobileOrderProduct> mobileOrderProducts;
#OneToMany(mappedBy = "orderProduct", fetch = FetchType.LAZY)
private List<TabletOrderProduct> tabletOrderProducts;
}
#Entity
#Table(name = "mobile_order_product")
public class MobileOrderProduct {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String mobileCode;
private String mobileNumber;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(referencedColumnName = "id", nullable = false)
#JsonIgnore
private MobileDevice mobileDevice;
#ManyToOne(fetch = FetchType.LAZY)
#JsonIgnore
#JoinColumn(referencedColumnName = "id", nullable = false)
private OrderProduct orderProduct;
}
#Entity
#Table(name = "mobile_device")
public class MobileDevice {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String serialNumber;
private String imei;
#OneToMany(mappedBy = "mobileDevice", fetch = FetchType.LAZY)
#JsonIgnore
private List<MobileOrderProduct> mobileOrderProducts;
}
Here I only included couple of my entity class because then you can understand the table structure correctly
public static Specification<Order> filterOrdersByGroupIdAndImei(int userGroupId, String imei) {
return (root, query, cb) -> {
List<Predicate> list = new ArrayList<Predicate>();
Join<Order, User> user = root.join("user");
Join<User, UserGroup> userGroup = user.join("userGroup");
Join<Order, OrderProduct> orderProduct = root.join("orderProducts", JoinType.INNER);
Join<OrderProduct, MobileDevice> mobileDevice = orderProduct
.join("mobileOrderProducts", JoinType.LEFT)
.join("mobileDevice", JoinType.LEFT);
Join<OrderProduct, TabletDevice> tabletDevice = orderProduct
.join("tabletOrderProducts", JoinType.LEFT)
.join("tabletDevice", JoinType.LEFT);
list.add(cb.equal(userGroup.get("id"), userGroupId));
list.add(cb.or(cb.equal(mobileDevice.get("imei"), imei), cb.equal(tabletDevice.get("imei"), imei)));
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
}

Persisting 2 table with the same generated id

I try to persist one parent entity which is joined with another child entity, but the problem is that the id is not generated for this child when persisting so I have this error : [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-01400: cannot insert NULL into ("L2S$OWNER"."SABRI"."TRANSITION_MATRIX_ID")
there is the child Entity :
#Data
#Entity
#IdClass(MyLibrarySabriEntityPK.class)
#Table(name = "SABRI", schema = "L2S$OWNER", catalog = "")
public class MyLibrarySabriEntity extends ActionForm {
#Access(AccessType.FIELD)
#Id
#ManyToOne
#JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;
#Id
private String RATING_ID_ROW;
#Id
private String RATING_ID_COL;
#Basic
#Column(name = "TRANSITION_PROBABILITY", nullable = true, insertable = true, updatable = true, precision = 20)
private Double TRANSITION_PROBABILITY;}
the PK class :
#Data
public class MyLibrarySabriEntityPK implements Serializable {
private String TRANSITION_MATRIX_ID;
private String RATING_ID_ROW;
private String RATING_ID_COL;
public MyLibrarySabriEntityPK(String TRANSITION_MATRIX_ID,String RATING_ID_COL,String RATING_ID_ROW ){
this.TRANSITION_MATRIX_ID=TRANSITION_MATRIX_ID;
this.RATING_ID_COL = RATING_ID_COL;
this.RATING_ID_ROW= RATING_ID_ROW;
}
}
there is the parent Entity:
#Data
#Entity
#Table(name = "TEST", schema = "L2S$OWNER", catalog = "")
public class MyLibraryTestEntity extends ActionForm {
#Access(AccessType.FIELD)
#OneToMany(mappedBy = "sabriEntity", cascade = CascadeType.PERSIST)
private final List<MyLibrarySabriEntity> entities = new ArrayList<MyLibrarySabriEntity>(25);
public void addEntitysabri(MyLibrarySabriEntity entity) {
getEntities().add(entity);
entity.setSabriEntity(this);
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "IdGenerated")
#GenericGenerator(name = "IdGenerated", strategy = "dao.Identifier")
#Column(name = "ID_TRANSITION_MATRIX", nullable = false, insertable = false, updatable = false, length = 10)
private String ID_TRANSITION_MATRIX;
#Basic
#Column(name = "REFERENCE", nullable = true, insertable = true, updatable = true, precision = 0)
private Integer reference;}
And here I try to persist the parent table which is supposed to persist also the child table but the Id is not generated !
MyLibrarySabriEntity Entity = null;
MyLibraryTestEntity test = getMyLibraryTestEntity(matrixStartDate, matrixName); // here I get the values of my entity test (parent)
try {
transaction.begin();
for (int row = 0; row < 20; row++) {
for (int col = 0; col < 20; col++) {
double val = cells.get(row + FIRST_ROW, col + FIRST_COL).getDoubleValue();
Entity = getMyLibrarySabriEntity(col, row, val); // this get the values of the Entity parameters (child)
Entity.setSabriEntity(test);
test.addEntitysabri(Entity);
em.persist(test);
}
}
} catch (Exception e) {
if (transaction.isActive())
transaction.rollback();
LOGGER.warn(e.getMessage(), e);
} finally {
if (transaction.isActive())
transaction.commit();
em.close();
}
Assuming you are using JPA 2.0+
Remove this mapping completely:
#Id
#Column(name = "TRANSITION_MATRIX_ID", nullable = false,
insertable = true, updatable = true, length = 100)
private String TRANSITION_MATRIX_ID;
and put the #Id directly on the ManyToOne and remove the insertable and updateable attributes.
#Access(AccessType.FIELD)
#Id
#ManyToOne
#JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;
Update your ID class accordingly. Any previous reference to TRANSITION_MATRIX_ID should be replaced with a reference to sabriEntity. You are also confusing #EmbeddedId and #IdClass: Only the former would contain column definitions whereas you are using the latter approach.
public class MyLibrarySabriEntityPK implements Serializable {
private String sabriEntity;
private String RATING_ID_ROW;
private String RATING_ID_COL;
}
See:
https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#JPA_2.0
Thank's to Alan Hay, I found the problem , I change the property TRANSITION_MATRIX_ID of my IDclass to sabriEntity and I delete all the annotation of this class !
Child entity
#Data
#Entity
#IdClass(MyLibrarySabriEntityPK.class)
#Table(name = "SABRI", schema = "L2S$OWNER", catalog = "")
public class MyLibrarySabriEntity extends ActionForm {
#Access(AccessType.FIELD)
#ManyToOne
#Id
#JoinColumn(name = "TRANSITION_MATRIX_ID", referencedColumnName = "ID_TRANSITION_MATRIX")
private MyLibraryTestEntity sabriEntity;
#Id
private String RATING_ID_ROW;
#Id
private String RATING_ID_COL;
#Basic
#Column(name = "TRANSITION_PROBABILITY", nullable = true, insertable = true, updatable = true, precision = 20)
private Double TRANSITION_PROBABILITY;
Parent Entity
#Data
#Entity
#Table(name = "TEST", schema = "L2S$OWNER", catalog = "")
public class MyLibraryTestEntity extends ActionForm {
#Access(AccessType.FIELD)
#OneToMany(mappedBy = "sabriEntity", cascade = CascadeType.PERSIST)
private final List<MyLibrarySabriEntity> entities = new ArrayList<MyLibrarySabriEntity>(25);
public void addEntitysabri(MyLibrarySabriEntity entity) {
getEntities().add(entity);
entity.setSabriEntity(this);
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "IdGenerated")
#GenericGenerator(name = "IdGenerated", strategy = "dao.Identifier")
#Column(name = "ID_TRANSITION_MATRIX", nullable = false, insertable = false, updatable = false, length = 10)
private String ID_TRANSITION_MATRIX;
#Basic
#Column(name = "REFERENCE", nullable = true, insertable = true, updatable = true, precision = 0)
private Integer reference;
PK Class
#Data
public class MyLibrarySabriEntityPK implements Serializable {
private MyLibraryTestEntity sabriEntity;
private String RATING_ID_ROW;
private String RATING_ID_COL;
public MyLibrarySabriEntityPK() {
}
public MyLibrarySabriEntityPK(MyLibraryTestEntity sabriEntity,String RATING_ID_COL,String RATING_ID_ROW ){
this.sabriEntity=sabriEntity;
this.RATING_ID_COL = RATING_ID_COL;
this.RATING_ID_ROW= RATING_ID_ROW;
}
}

Hibernate Exception - could not locate named parameter

i am trying to extract a list of objects from database from entity (table) StudySeries:
#Entity
#Table(name="StudySeries", uniqueConstraints = {
#UniqueConstraint(columnNames = "SeriesInstanceUID")})
public class StudySeries implements Serializable {
...
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "SeId", unique = true, nullable = false)
private Long seId;
#Column(name="SeriesInstanceUID", unique=true, nullable = false)
private String seriesInstanceUID;
...
#ManyToOne
#JoinColumn(name = "StId", referencedColumnName="StId")
private StudyDetails studyDetails;
...
}
This entity is N-1 joined with StudyDetails (on StudyDetails has many StudySeries):
#Entity
#Table(name="StudyDetails", uniqueConstraints = #UniqueConstraint(columnNames = "StudyInstanceUID"))
public class StudyDetails implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name="StId", unique = true, nullable = false)
private Long stId;
#Column(name="StudyInstanceUID", unique=true, nullable = false)
private String studyInstanceUID;
...
#OneToMany(fetch = FetchType.LAZY, mappedBy = "studyDetails", cascade = CascadeType.ALL)
private Set<StudySeries> studySeries = new HashSet<StudySeries>(0);
...
}
In my StudySeriesDAOImpl() i am trying to:
#Override
public List<StudySeries> getStudySeriesObjectsByStudyId(Long stId) {
List<StudySeries> results=new ArrayList<>();
Session s=HibernateUtil.openSession();
s.beginTransaction();
String hql = "from StudySeries E where E.studyDetails.stId = stId";
Query query = s.createQuery(hql);
query.setParameter("stId", stId);
results = query.list();
s.getTransaction().commit();
s.close();
log.info(">>>>> list size: " + results.size());
return results;
}
I have also tried the hql query as:
String hql = "from StudySeries E where E.stId = stId";
However i am getting:
org.hibernate.QueryParameterException: could not locate named parameter [stId]
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100) at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100)
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:106)
at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:466)
at org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:436)
at com.npap.dao.StudySeriesDAOImpl.getStudySeriesObjectsByStudyId(StudySeriesDAOImpl.java:239)
Any ideas what is wrong?
In the StudySeries class, the id is named as 'seId', not 'stId'.
You should do like this: String hql = "from StudySeries E where E.seId = stId";

JPQL join condition in linked Entity class

I'm using the following SQL to join employees, user_projects and project_master
SELECT DISTINCT usr.user_number,
emp.emp_name
FROM employees emp
LEFT JOIN user_projects usr
ON (emp.user_number = usr.user_number)
JOIN project_master mast
ON (usr.project_id = mast.project_id)
WHERE mast.active = 'Y'
AND emp.user_number = 'SMITH'
In Employee entity, I have the following JPQL defined as namedQuery
#NamedQuery(name = "Employee.findProjects", query = " select DISTINCT u.userNumber,e.empName" +
" from Employee e LEFT JOIN e.userProjectsList u where e.userNumber='SMITH' ")
Not sure how to link UserProjects and ProjectMaster to create a where condition
mast.active = 'Y' in Employee entity's findProjects namedQuery
How to join UserProjects and ProjectMaster in Employee Entity class?
Entities
Entity Employee
#Table(name = "EMPLOYEES")
public class Employee implements Serializable {
#Id
#Column(name = "USER_NUMBER", nullable = false)
private String userNumber;
#Column(name = "EMP_NAME")
private String empName;
#OneToMany(mappedBy = "employee")
private List<UserProjects> userProjectsList;
Entity UserProjects
#Table(name = "USER_PROJECTS")
public class UserProjects implements Serializable {
#Id
#Column(name="PROJECT_ID", nullable = false, insertable = false,
updatable = false)
private String projectId;
#Id
#Column(name="USER_NUMBER", nullable = false, insertable = false, updatable = false)
private String userNumber;
#ManyToOne
#JoinColumn(name = "PROJECT_ID", referencedColumnName = "PROJECT_ID")
private ProjectMaster projectMaster;
Entity ProjectMaster
#Table(name = "PROJECTMASTER")
public class ProjectMaster implements Serializable {
#Id
#Column(name="PROJECT_ID", nullable = false)
private String projectId;
#Column(name="PROJECT_DESCRIPTION")
private String projectDesc;
#Column(name="ACTIVE")
private String active;
select DISTINCT u.userNumber,e.empName from Employee e LEFT JOIN
e.userProjectsList u JOIN u.projectMaster pm
where e.userNumber='SMITH' AND pm.active='Y'
Isn't this work?

Categories