spring-data-rest, manytomany relation with join table - java

Is it possible to expose a manytomany relationship that uses a join entity (that contains extra data columns), below is my entities;
I'm trying to get 'purchases' to show in REST, I've put in 'products' as an example of a working REST mapping;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = Purchase.class, orphanRemoval = true)
#JoinColumn(name = "user_id", updatable = false)
private List<Purchase> purchases = new ArrayList<>();
#ManyToMany
#JoinColumn(name = "user_id", updatable = false)
private List<Product> products = new ArrayList<>();
}
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
#Entity
public class Purchase implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
#ManyToOne(targetEntity = Prodect.class)
#JoinColumn(name = "product_id", referencedColumnName = "id")
private Product product;
#Column(name = "purchase_date")
private Date purchaseDate;
}
So if i send the REST call;
[GET http://localhost:8080/webapp/users/1]
It returns links for [http://localhost:8080/webapp/users/1/products] but not for [http://localhost:8080/webapp/users/1/purchases]

worked out what the issue was; I need to create a JpaRepository for the Purchase entity. Soon as I added that, the REST links for purchases are available.

Related

Why unidirectional instead of bidirectional?

So I'm following a Spring Boot tutorial online, and I have two Java classes, which are entities: Order and Address:
Order.java:
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// more properties
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "shipping_address_id", referencedColumnName = "id")
private Address shippingAddress;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "billing_address_id", referencedColumnName = "id")
private Address billingAddress;
}
Address.java:
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// more properties
#OneToOne
#PrimaryKeyJoinColumn
private Order order;
}
Is this a bidirectional relationship (even though neither entity has a #JoinColumn with a mappedBy attribute) or is this two unidirectional relationships, Order->Address and Address->Order?

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 ......

How to map only values of HashMap - Hibernate

I'd like to map only the values of a map to database.
In the example below, in class Holder, there's a map of ID, Entity, being the ID a BigInteger and the entity Item.
I'm doing this because I want fast search and hashmap K,V is good for that.
But, now, the mapping is weird.
The JoinTable holder_items now has 3 columns, holder_id. item_id and item_KEY.
Can I have only older_id and item_Id?
Basically, mapping only items.values() to the current Holder.
#Entity
public class Holder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "holder_items",
joinColumns = #JoinColumn(name = "holder_id"),
inverseJoinColumns = #JoinColumn(name = "item_id")
)
private Map<BigInteger, Item> items = new HashMap<>();
//(...)
}
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "BIGINT")
private BigInteger id;
//(...)
}
You could do this mapping without the third table if it is not necessary ofc. Example:
#Entity
public class Holder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#MapKey(name = "id")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="holder")
private Map<BigInteger, Item> items = new HashMap<>();
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "BIGINT")
private BigInteger id;
#ManyToOne
private Holder holder;
}
Solution with help of #Anthony
#Entity
public class Holder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#MapKey(name = "id")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "holder_items",
joinColumns = #JoinColumn(name = "holder_id"),
inverseJoinColumns = #JoinColumn(name = "item_id")
)
private Map<BigInteger, Item> items = new HashMap<>();
-
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "BIGINT")
private BigInteger id;
}
Results in table holder_items with holder_id and item_id, as desired!

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
}

Select records without parent with Hibernate using Criteria API

How select records without parent with Hibernate using Criteria API?
Here is my Java code for select with parents
getSessionFactory().getCurrentSession().createCriteria(Category.class).add(
Restrictions.eq("parent", new Category(parentId))).list();
Category Java code
#Entity
#Table(name = "CATEGORY")
public class Category implements NamedModel{
#Id
#Column(name = "CATEGORY_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
#JoinTable(name = "CATEGORY_RELATIONS",
joinColumns = {
#JoinColumn(name = "CATEGORY_RELATIONS_CATEGORY_ID", referencedColumnName = "CATEGORY_ID")},
inverseJoinColumns = {
#JoinColumn(name = "CATEGORY_RELATIONS_PARENT_ID", referencedColumnName = "CATEGORY_ID")})
private Category parent;
#OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, mappedBy = "parent")
private List<Category> children;//...
}
CategoryRelations Java code
#Entity
#Table(name = "CATEGORY_RELATIONS")
#IdClass(CategoryRelations.CategoryRelationsPrimaryKey.class)
public class CategoryRelations implements Serializable {
#Id
#Column(name = "CATEGORY_RELATIONS_CATEGORY_ID")
private long categoryId;
#Id
#Column(name = "CATEGORY_RELATIONS_PARENT_ID")
private long parentId;
#Entity
#IdClass(CategoryRelationsPrimaryKey.class)
public static class CategoryRelationsPrimaryKey implements Serializable {
private long categoryId;
private long parentId;
}
}
You can use Restriction#isNull(propertyName) function for your requirements.
Restrictions.isNull("parent")

Categories