Hibernate one to one criteria fetching - java

I am using hibernate one to one mapping between car and person table. But a person might have car and might not have a car. now while fetching the records from the person table using hibernate criteria , I want to fetch only those persons who have a car, i.e only those entries in person table for which a corresponding entry in car table exists. How this can be done using hibernate criteria/alias?
Below is the piece of code. kindly help with the criteria or alias that has to written to fetch result:
#Getter
#Setter
#Entity
#Table(name = "Person")
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Person_ID")
private Long personId;
#OneToOne(mappedBy = "personAsset", cascade = CascadeType.ALL)
private Car car;
}
#Getter
#Setter
#Entity
#Table(name = "Car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Car_ID")
private Long carId;
#OneToOne
#JoinColumn(name = "Person_ID")
private Person personAsset;
}

what you are looking for is the cascadeType orphanRemoval=true on the #OneToOne annotation.
here is your class how would look like :
#Getter
#Setter
#Entity
#Table(name = "Car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Car_ID")
private Long carId;
#OneToOne(fetch=FetchType.EAGER , cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name = "Person_ID")
private Person personAsset;
}

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> person = query.from(Person.class);
Predicate predicate = cb.isNotNull(person.join("car"));
predicates.add(predicate );

Related

How to get parent entity with all child entities and child entities of children in Spring/JPA/Hibernate with Lombok

I have these entities where Shop entity is parent:
#Data
#NoArgsConstructor
#Entity
#DynamicUpdate
#Table(name = "Shop", schema = "public")
public class ShopDao {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String name;
private String processedStatus;
#OneToMany(mappedBy = "shopDao", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BookDao> bookDaoList;
}
#Data
#NoArgsConstructor
#Entity
#ToString(exclude = {"shopDao"})
#Table(name = "Book", schema = "public")
public class BookDao {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String name;
private String author;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "other_id", referencedColumnName = "id")
private OtherDao otherDao;
#ManyToOne
#JoinColumn(name = "shop_id", nullable = false)
private ShopDao shopDao;
}
#Data
#NoArgsConstructor
#Entity
#ToString(exclude = {"bookDao"})
#Table(name = "Other", schema = "public")
public class OtherDao {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String metadata;
#OneToOne(mappedBy = "otherDao", fetch = FetchType.EAGER)
private BookDao bookDao;
}
And these are repos:
#Repository
public interface ShopRepo extends JpaRepository<ShopDao, Long> {
#EntityGraph(attributePaths = {"bookDaoList"})
List<ShopDao> findAllByProcessedStatus(String processedStatus);
}
#Repository
public interface BookRepo extends JpaRepository<BookDao, Long> {
}
#Repository
public interface OtherRepo extends JpaRepository<OtherDao, Long> {
}
When i'm using findAllByProcessedStatus() function, i get BookList inside Shop object correctly, but each Book can't reach their Other objects and i get LazyInitializationException:
screenshot
How do i fix that problem?
Actually, with spring data's #EntityGraph all you need is :
#Repository
public interface ShopRepo extends JpaRepository<ShopDao, Long> {
#EntityGraph(attributePaths = {"bookDaoList.otherDao"})
List<ShopDao> findAllByProcessedStatus(String processedStatus);
}
This is the most convenient way.
For more complex relations, you could define a #NamedEntityGraph, and provide subgraphs, like so.
What I find intriguing, is that the BookDao is the owner of this relation, so I would expect it to be eagerly loaded, since you haven't specified a the Lazy fetch mode explicitly ...

Create query which selects by checking items in related list

I have Shop entity:
#Entity
#Table(name = "shop")
public class Shop {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="shop_id")
private List<OpenDay> openDays = new ArrayList<>();
}
and OpenDay entity:
#Entity
#Table(name = "open_day")
public class OpenDay {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate date;
}
I need a query which will select all Shop which have OpenDay with date set to particular dates, let's say for today and tomorrow so I select shops which are open today and tomorrow.
How can I achieve this?
Criteria API is preferred so I will be able to use it with spring-data-jpa Specification. Thank you.
As far as I understand open_day table contains shop_id column. So I suggest you to add Shop field to OpenDay entity.
#Entity
#Table(name = "open_day")
public class OpenDay {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate date;
#ManyToOne
#JoinColumn(name="shop_id")
private Shop shop;
}
And then
EntityManager entityManager;
public List<Shop> getShopsByOpenDates(List<LocalDate> dates) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Shop> query = builder.createQuery(Shop.class);
Root<OpenDay> openDay = query.from(OpenDay.class);
Predicate predicate = openDay.get("date").in(dates);
query.select(openDay.get("shop")).distinct(true).where(predicate);
return entityManager.createQuery(query).getResultList();
}

Hibernate #embededId containing a foreign key of an entity with inheritance

Used this as my base point: https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/
I have an entity named Attendance that has an and emebedid AttendacneId that has two columns lectureId (string) and studenId(UUID). The attendance entity also has other properties as well containing a ManyToOne relationship with student and lecture enity using the #MapsId on them. The student extends user entity where the id resides. now when I try to save anything I get this error.
java.util.NoSuchElementException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at org.hibernate.cfg.annotations.TableBinder.linkJoinColumnWithValueOverridingNameIfImplicit(TableBinder.java:724)
at org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass.doSecondPass(PkDrivenByDefaultMapsIdSecondPass.java:37)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1684)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1641)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:286)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:473)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:84)
at utility.Utils.<clinit>(Utils.java:60)
at utility.Testing.main(Testing.java:21)
My AttendanceId class
#Embeddable
public class AttendanceId implements Serializable {
#Column(name = "lecture_fid")
#Getter
#Setter
private String lectureId;
#Column(name = "student_fid", columnDefinition = "uuid")
#Getter
#Setter
private UUID studentId;
public AttendanceId() {}
}
My Attendance class
#Entity
#Table(name = "attendance")
public class Attendance implements Serializable {
#EmbeddedId
#Getter
#Setter(AccessLevel.PRIVATE)
private AttendanceId id;
// other fields
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("lectureId")
private Lecture lecture;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("studentId")
private Student student;
}
My Student Class
#Entity
#PrimaryKeyJoinColumn(name = "id")
public class Student extends User implements Serializable,
Comparable<Student> {
// other fields
#OneToMany(mappedBy = "student", fetch = FetchType.LAZY)
#Getter
private List<Attendance> attendances = new ArrayList<>();
}
My User class
#Entity
#Table(name = "users", uniqueConstraints = {
#UniqueConstraint(columnNames = {"email", "username"})})
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class User implements Serializable {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid")
#Column(columnDefinition = "UUID")
#Getter(AccessLevel.PUBLIC)
#Setter(AccessLevel.PUBLIC)
private UUID id;
// other fields.
}
My Lecture Class
#NamedNativeQueries(
#NamedNativeQuery(name = "getLectureId", query = "select
get_lecture_id()")
)
#Entity
#Table(name = "lecture")
public class Lecture implements Serializable {
#Id
#Column(name = "id")
#GenericGenerator(name = "lectureIdGenerator",
strategy = "entities.LectureIdGenerator")
#GeneratedValue(generator = "lectureIdGenerator")
#Getter
#Setter
private String id;
#OneToMany(mappedBy = "lecture", fetch = FetchType.LAZY)
#Getter
private List<Attendance> attendances = new ArrayList<>();
// other fields
}
I think the inheritance is causing an issue. There are other classes/entities as well that extends the user entity. If anyone could help me find the problem that will be great. Thank you.
This issue is caused by the HHH-7135 Hibernate issue.

Hibernate/JPA incorrect join in Spring Boot Application

See code below for my 2 entity classes - when I call the findAll() method from my OrigRepository class, it joins these two tables using both primary keys. I want the join to be between the primary key of the Orig table and the foreign key entry in the MsgResponse table ("OrigID") - any sugggestions?
Orig Entity
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private MsgResponse responseInfo;
}
MsgResponse Entity
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
#Column(name = "OrigID")
private int OrigId;
#OneToOne(mappedBy="responseInfo")
private Orig OrigInfo;
}
I suggest you to see the jpa documentation
here.
Example 1 should be your case
Try to swap relation ownership, that is:
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(mappedBy="origInfo")
private MsgResponse responseInfo;
}
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
// #Column(name = "OrigID")
// private int origId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private Orig origInfo;
}
Note that the #JoinColum annotation is in now in the MsgResponse entity. This is because in a #OneToOne the join column refers to the source entity (see here).
Hope this could help.

jpa one-to-many self reference is fetching all levels

I'm trying to create a social app service. I have user with confirmed or nonconfirmed relationships.
When I load UserA, the result look like belove.
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":[
{
"idUser":"UserC",
"unconFriendships":[
...
While it has to be look like
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":null //only one level have to fetched
....
I thought that this was because jackson json library, I debbuged the code. Before serialization, I inspected userA object and I saw that userA.unconFriendships.userB.unconFriendships was not null and with size bigger than 0.
Nearly it has been 12 hours, still couldn't solve the problem. Please help me to solve this. Thanks in advence.
Here is UserEntity.java
#Entity
#Table(name="aduser",uniqueConstraints=#UniqueConstraint(columnNames = {"idUser","nmEmail"}))
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="cdUser")
public class UserEntity extends BaseEntity {
protected static final long serialVersionUID = 8864033727886664353L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "admin_seq")
#SequenceGenerator(name = "admin_seq", sequenceName = "CDUSER_SEQUENCE", allocationSize = 1)
#Column(name="cdUser")
private long cdUser;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> unconFriendships;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> conFriendships;
...
Friendship.java
#Entity
#Table(name="aduserfriend")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "verified")
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="friend_cduser",scope=UserEntity.class)
public abstract class Friendship extends BaseEntity{
protected static final long serialVersionUID = -670863816551430192L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "cdFriendship")
private long cdFriendship;
#ManyToOne
#JsonIgnore
#JoinColumn(name = "owner_cduser")
protected UserEntity owner;
#ManyToOne
#JoinColumn(name = "friend_cduser")
protected UserEntity friend;
#Column(name = "verified",insertable=false,updatable=false)
private boolean verified;
...
UnconfirmedFriendship.java and ConfirmedFriendship.java
#Entity
#DiscriminatorValue(value = "0")//this value is 1 for Confirmed relationship
public class UnconfirmedFriendship extends Friendship {
private static final long serialVersionUID = 57796452166904132L;
}

Categories