How works Hibernate #ManyToMany relationship? - java

I have 3 entities and one entity for linking these three entities:
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "a", fetch = FetchType.LAZY)
private List<ABCXref> abcXref = new ArrayList<ABCXref>();
// getters/setters
}
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "b", fetch = FetchType.LAZY)
private List<ABCXref> abcXref = new ArrayList<ABCXref>();
// getters/setters
}
#Entity
public class C {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "c", fetch = FetchType.LAZY)
private List<ABCXref> abcXref = new ArrayList<ABCXref>();
// getters/setters
}
#Entity
public class ABCXref {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JoinColumn(name = "A_ID", nullable = true)
#ManyToOne(optional = true, fetch = FetchType.LAZY)
private A a;
#JoinColumn(name = "B_ID")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private B b;
#JoinColumn(name = "C_ID")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private C c;
}
The question is: does all instances of A, B and C share the same list of ABCXref's? What if I add new ABCXref to A instance? Does this ABCXref appear in list of ABCXrefs of B and C?
I.e. will this code output true?
println(b.getAbcXref().size()); //0
c.getAbcXref().add(new ABCXref(a, b, c));
println(b.getAbcXref().size() == 1) //is `true` or `false`?

Related

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!

How do you properly map a list in hibernate

I'm trying to implement a config-database using MariaDB and Hibernate in Java. Let A be a Person who can have B Licenses. Each license b consists of a list of Cs (some object which holds a string and an int).
class A {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "b_id")
List<B> bs;
}
class B {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "b_id")
private long id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "c_id")
List<C> bs;
}
class C {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "c_id")
private long id;
String blabla;
int i;
}
I can get it to save, however I can not get it to update without leaving redundant fields when resaving the changed A (load A from database -> add B to A's Bs / add C to B's Cs -> save -> redundant fields stay in database).
What is the proper way to do this?
So far I tried using #ElementCollection, CascadeType.persist and orphanRemoval = true with no luck.
Add updatable false in #JoinColumn So it will not change child tables while saving parent
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "b_id",updatable=false)
List<B> bs;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "c_id",updatable=false)
List<C> bs;

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")

spring-data-rest, manytomany relation with join table

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.

Categories