How to Query referenced tables in JPA Spring - java

I have 4 models:
Blueprint, that describes a single type of Item:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#ElementCollection
#CollectionTable(name = "BLUEPRINT_TAG", joinColumns = #JoinColumn(name = "blueprint"))
private List<String> tags;
#OneToMany(mappedBy = "blueprint", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BlueprintProperty> properties;
#OneToMany(mappedBy = "blueprint", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
private List<Item> items;
#Column(name = "width")
private Float width;
#Column(name = "height")
private Float height;
#Column(name = "imagePath")
private String imagePath;
#Column(name = "zPosition")
private long zPosition;
BlueprintProperty, that describes what information can be entered for each type of Item.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "blueprint")
#JsonIgnore
private Blueprint blueprint;
#Column(name = "name")
private String name;
#Enumerated(EnumType.STRING)
private PropertyType type;
#Column(name = "data")
#Convert(converter = JpaJsonConverter.class)
private ObjectNode data;
#OneToMany(mappedBy = "property", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
private List<ItemProperty> itemProperties;
Then there's Item:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "parent")
//#Nullable
private Item parent;
#Column(name = "pos_x")
private Float posX;
#Column(name = "pos_y")
private Float posY;
#Column(name = "transformation")
private String transformation;
#ManyToOne
#JoinColumn(name = "blueprint")
private Blueprint blueprint;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
#JsonIgnore
private List<Item> children;
#OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ItemProperty> properties;
And finally, ItemProperty, that holds foreign keys referencing Item the specific property belongs to, and BlueprintProperty it's describing:
#Id
#ManyToOne
#JoinColumn(name = "item")
#JsonIgnore
private Item item;
#Id
#ManyToOne
#JoinColumn(name = "property")
#JsonIgnore
private BlueprintProperty property;
#Column(name = "value")
private String value;
Now, I'm not exactly happy with this setup, but that's what I have to work with and unless completely necessary I shouldn't change anything. What I'm trying to do is create a Query that takes a number of Item properties and returns all Items which properties match the query.
Using Query by example sounded promising, but I found out that only SingularAttribute properties can currently be used for property matching.. So that killed that approach, and I don't think I can use native query, because a certain Item can have N properties, and you should be able to enter a query that searches by a single property, up to N properties.
Can someone suggest a way to perform the search I need and get a List of Items matching whose properties matched those entered as a result?

Related

HQL query doesn't order by other mapped entity criteria

I have the following entities in a Hibernate - Spring proyect.
Member:
#Entity
#Table(name = "member")
public class Member implements Serializable {
private static final long serialVersionUID = 1871629487715861212L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "ident_doc")
private String identDoc;
#Column(name = "join_date")
private String joinDate;
private String nickname;
#OneToOne(mappedBy = "member")
private MemberContact memberContact;
#OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<MemberChapterLog> memberChapterLogs;
#OneToMany(mappedBy = "member")
private List<ChapterOfficers> chapterOfficers;
#OneToOne(mappedBy = "contactMember", cascade = CascadeType.ALL)
private Chapter asChapterContact;
Chapter:
#Entity
#Table(name = "chapter")
#NamedQuery(
name = "Chapter_Get_Detailed_Members_List",
query = "from MemberChapterLog where chapter.id = :paramChapter and active = true "+
"order by member.lastName asc")
public class Chapter implements Serializable {
private static final long serialVersionUID = -8387387246818721664L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String initials;
#Column(name ="chap_name")
private String chapName;
#ManyToOne
#JoinColumn(name = "category")
private ChapCategory category;
#OneToOne
#JoinColumn(name = "contact_member")
private Member contactMember;
#OneToOne(mappedBy = "chapter", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private ChapterContact chapterContact;
#OneToMany(mappedBy = "chapter")
private List<MemberChapterLog> memberChapterlogs;
#OneToMany(mappedBy = "chapter")
private List<ChapterOfficers> chapterOfficers;
MemberChapterLog:
#Entity
#Table(name = "member_chapter_log")
public class MemberChapterLog implements Serializable {
private static final long serialVersionUID = -643503606583240644L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
#ManyToOne
#JoinColumn(name = "chapter_id")
private Chapter chapter;
#Column(name = "log_date")
private String logDate;
private String comment;
private boolean active;
I want to get a list of the active members of certain chapter (passed as ':paramChapter'), order by their last name. When I run the named query at chapter ("from MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc") it generates the following error:
org.hibernate.HibernateException: Errors in named queries:
Chapter_Get_Detailed_Members_List failed because of: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: member near line 1, column 105 [from dev.xarlsr.cdt.entity.MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc]
If I delete the order by member.lastName it works properly (without any order, byt the way).
I tried to change the mapping by changing the tables foreign keys and the ownership, but doesn't work. I tried to change the fetch type without results. What am I doing wrong?
The problem is the mapping:
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
member is a keyword in JPQL/HQL and soft-keyword handling was only introduced in Hibernate 6, so you will need to change the name of the field to e.g. memberAssociation and the query condition to ... order by memberAssociation.lastName asc

How to make JPA query method about onetomany?

I'm stuck at deal with this problem. I have 'Review Entity', and 'Heart Entitiy'. And I tried to show them homepage and detailpage separately!
Long countHeartByBookReviewId(Long bookReview_id);
i used jpa query method for showing how many heart it gets in details page..
and now i want to show review descending related to heart count in main page!
how can i make the code..?
#Entity
public class BookReview extends Timestamped {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
...
#Column
private String review;
#JoinColumn(name = "member_id", nullable = false)
#ManyToOne(fetch = FetchType.EAGER)
private Member member;
#OneToMany(mappedBy = "bookReview" , cascade = CascadeType.REMOVE)
private List<Comment> comment;
#JsonIgnore
#OneToMany(mappedBy = "bookReview", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Heart> heart;
and the other entitiy is here.
public class Heart {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "bookReview_id")
private BookReview bookReview;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "member_id")
private Member member;
and this is function for get menthod...
public ResponseDto<?> getHome() {
List<BookReview> book_review = book_reviewRepository.findAllByOrderByHeartDesc();
List<HomeResponseDto> book_reviewResponseDtoList = new ArrayList<>();
for (BookReview home : book_review) {
book_reviewResponseDtoList.add(HomeResponseDto.builder()
.id(home.getId())
.username(home.getMember().getUsername())
.thumbnail(home.getThumbnail())
.title(home.getTitle())
.author(home.getAuthor())
.publisher(home.getPublisher())
.review(home.getReview())
.heart(heartRepository.countHeartByBookReviewId(home.getId()))
.createdAt(home.getCreatedAt())
.modifiedAt(home.getModifiedAt())
.build()
);
}
return ResponseDto.success(book_reviewResponseDtoList);
}
please help me ......

ManyToMany relationship entries are not being displayed in Spring REST

I have two classes: MenuItem.java and Tag.java. I am using the Hibernate implementation of JPA, and using PagingAndSortingRepository. After creating a bunch of dummy MenuItems and Tags, these are displayed in my local database and can be accessed with either: localhost:8080/api/menuItems or localhost:8080/api/tags. Additionally, as described by my annotations in the files below, there exists a ManyToMany relationship between these two objects, and a Menu_Items_Tags table with the appropriate entries is also created in my database without any issue.
The problem I run into is that every time I attempt to access a given menu item's list of tags via: localhost:8080/api/menuItems/1/tags for example, I receive a 500 error and additionally have a repeating error code like this:
: HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext#726b0462<rs=HikariProxyResultSet#1877641821 wrapping Result set representing update count of 6>
Is there something I am doing wrong in either trying to request the Tags of a MenuItem or am I incorrectly setting up my #ManyToMany relationship?
MenuItem.java:
#Data
#Entity
public class MenuItem implements Serializable {
private static final long serialVersionUID = 1132661429342356177L;
public MenuItem() {
}
public MenuItem(String name, Double price, Integer inventory, String description, Set<Tag> tags) {
this.name = name;
this.price = price;
this.inventory = inventory;
this.description = description;
this.tags = tags;
}
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#Column(name = "name", nullable = false, unique = true)
private String name;
#Column(name = "price", nullable = false)
private Double price;
#Column(name = "inventory", nullable = false)
private Integer inventory;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(mappedBy = "menuItem")
private Set<Order> orders;
#ManyToMany
#JoinTable(
name="menu_item_tags",
joinColumns = #JoinColumn(name = "menu_item_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "tag_id", referencedColumnName = "id"))
#JsonManagedReference
private Set<Tag> tags;
}
Tag.java:
#Data
#Entity
public class Tag implements Serializable {
private static final long serialVersionUID = 1132661429342356176L;
public Tag() {
}
public Tag(String name) {
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name", unique = true)
private String name;
// #JsonIgnore
#ManyToMany(mappedBy = "tags")
#JsonBackReference
private Set<MenuItem> menuItems;
}

Java Hibernate Database speed issue

I generated application using Jhipster. In start everything was working fine but as application grow tournament entity become issue regarding performances.
This is my entity :
/**
* A Tournament.
*/
#Entity
#Table(name = "tournament")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "tournament")
public class Tournament implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "location")
private String location;
#Column(name = "url")
private String url;
#Column(name = "start_date")
private ZonedDateTime startDate;
#Column(name = "end_date")
private ZonedDateTime endDate;
#Column(name = "entry_fee")
private Double entryFee;
#Column(name = "prize")
private Double prize;
#Column(name = "goods")
private String goods;
#Column(name = "favorite_rating")
private Long favoriteRating;
#Column(name = "participants_number")
private Integer participantsNumber;
#Column(name = "finished")
private Boolean finished;
#Column(name = "view_only")
private Boolean viewOnly;
#Column(name = "image")
private String image;
#Column(name = "description")
private String description;
#Column(name = "teams_applied")
private String teamsApplied;
#Lob
#Column(name = "schedule")
private String schedule;
#Lob
#Column(name = "prize_distribution")
private String prizeDistribution;
#Lob
#Column(name = "contacts")
private String contacts;
#Lob
#Column(name = "rules")
private String rules;
#OneToMany(mappedBy = "tournament", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Stream> streams = new HashSet<>();
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "tournament_platforms", joinColumns = #JoinColumn(name = "tournaments_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "platforms_id", referencedColumnName = "id"))
private Set<Platform> platforms = new HashSet<>();
#ManyToMany(mappedBy = "favoriteTournaments", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<User> favoriteUsers = new HashSet<>();
#ManyToOne
private Game game;
#ManyToOne
private TournamentStatus status;
#ManyToOne
private EntryType entryType;
#ManyToOne
private TournamentFormat format;
#ManyToOne
private Region region;
#ManyToOne
private GameMode gameMode;
#ManyToOne
private PrizeType prizeType;
#ManyToOne
private Organizer organizer;
#ManyToOne
private TournamentStage stage;
#ManyToOne
private HostPlatform hostPlatforms;
#ManyToOne
private TournamentType type;
#ManyToOne
private PlayType playType;
#ManyToOne
private Currency currency;
#ManyToOne
private Country country;
I am using spring JPA. Getting 20 tournaments from database takes 39 seconds. That is not acceptable. Is there any way i can reduce it to normal speed. What is reason for such a long response time ? Every many to one relation i made unidire
In hibernate's implementation of JPA, #ManyToOne has a fetchType = EAGER by default and you have 14 of them.
#ManyToOne
private Country country;
That means 14 joins for each request. I highly recommend to use fetchType = LAZY for all relationships and deactivate them one by one when needed.
As a rule of thumb, you should not use more than 3 joins per request.
Also take a look at the generated request and use EXPLAIN PLAN in order to understand what the database really does and where it is costly. It will probably reveal some missing indexes on columns used as foreign keys...

Hibernate loads list collection twice

I have 3 tables in my database, container, item and item_container which is a join_table of many to one between container and item. Entities in code are mapped using 2 classes: Container and Item.
The relation is unidrectional from Container to Item.
join_table in hibernate is mapped only by annotations in Container class.
#Entity
#Table(name="container")
public class Container {
#Id
#Column(name = "container_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinTable(name = "item_container",
joinColumns = #JoinColumn(name = "container_id"),
inverseJoinColumns = #JoinColumn(name = "item_id"))
private Set<Item> items;
//getter/setters
}
My problem is: when i have the type of collection Set<Item> items changed to List<Item>, the list contain every Item entity twice. I cant find the reason why, the hashCode and equals methods of Item are based only on the item_id field.
UPDATE:
Code for Item class:
#Entity
#Table(name = "item")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "item_template_id", nullable = false)
private ItemTemplate itemTemplate;
#Column(name = "item_group")
#Enumerated(EnumType.STRING)
private ItemGroup itemGroup;
#Column(name = "amount")
private int amount;
//getter/setters
}

Categories