19 Şubat 2019 Salı

JPA @ManyToMany İlişki - Ara Tablo Kullanmayan

Giriş
ManyToMany bidirectional ilişkide bir sınıfı sadece @ManyToMany (mappedBy) şeklide diğer sınıf ise @ManyToMany ve @JoinTable olarak tanımlanır.

Bu ilişki EAGER. Açıklaması şöyle
OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER
Set vs List
Açıklaması şöyle
Use Set instead of List while defining many-2-many relations. Because if you delete or insert an entity object in this List then instead of one query to delete or insert, spring data JPA will drop all elements of List and then reinsert the concerning objects again.

Veritabanı Açısından Owner Taraf
@JoinTable anotasyonu tanımlayan sınıf veri tabanı açısından owner taraftır.  Önce bu sınıf kaydedilir. Hani tarafın owner olacağının seçimi bir muamma. Her iki tarafı owner yapmak mümkün. Açıklaması şöyle.
In the case of ManytoMany relationships in bidirectional scenario the Owner of the relationship can be selected arbitrarily, but having in mind the purpose you should select the entity that makes more sense to retrieve first or the one that is more used according to your purpose. You only need to remember that Many always need to be the owning side in ManyToOne scenarios.
Örnek
Şöyle yaparız. Veritabanı açısından owner taraf Event tablosudur.
@Entity
public class Event {
  @ManyToMany(fetch = FetchType.LAZY,cascade = {CascadeType.PERSIST,CascadeType.MERGE})
  @JoinTable(
        name = "event_registrations",
        joinColumns = @JoinColumn(name="event_id", referencedColumnName = 
        "id"),
        inverseJoinColumns = @JoinColumn(name = "user_id", 
        referencedColumnName = "id"))
  private List<User> userList;
  ...
}
Diğer tarafta şöyle yaparız. Kod açısından ise owner tarafa mappedBy anotasyonunu kullanan User nesnesidir.
@Entity
public class User {
  @ManyToMany(fetch = FetchType.LAZY,cascade = {CascadeType.PERSIST,CascadeType.MERGE},
        mappedBy = "userList")
  private List<Event> eventRegistrations;
  ...
}

cascade Alanı
Örnek
Owning side şöyle olsun.
@Entity
@Table(name = "product_details")
public class ProductDetails {

  private int productId;
  private String productName;

  @ManyToMany(cascade = { CascadeType.ALL })
  @JoinTable(
    name = "order_product", 
    joinColumns = { @JoinColumn(name = "productId") }, 
    inverseJoinColumns = { @JoinColumn(name = "orderId") }
  )
  private Collection<OrderDetails> orders = new ArrayList();
  ...
}
Diğer taraf şöyle olsun.
@Entity
@Table(name = "order_details")
public class OrderDetails {

  private int orderId;
  private String orderName;
  @ManyToMany(mappedBy = "orders")
  private Collection<ProductDetails> products = new ArrayList();
  ...
}
Örnek
Şöyle yaparız.
@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
@JoinTable(
        name = "profile_skills",
        joinColumns = @JoinColumn(name = "profile_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "skill_id", referencedColumnName = "id")
)
private Set<Skill> skills;
fetch Alanı
Örnek
Şöyle yaparız
public class Course {

    @Id
    @GeneratedValue
    private int id;

    @ManyToMany(mappedBy = "courses", fetch = FetchType.EAGER,cascade = 
    {CascadeType.ALL})
    private Set<Student> students;
}
Şöyle yaparız
@Entity
public class Student {

@Id
@GeneratedValue
private int id;


@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name = "stud_course", joinColumns ={ @JoinColumn(name = "student_id",
  referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "course_id",
  referencedColumnName = "id")})
private Set<Course> courses;
targetEntity Alanı
Örnek
A sınıfı şöyle olsun
@Entity
public class A {

  @Column(name = "a_id")
  String id;
  
  @ManyToMany(targetEntity = B.class,
              cascade = { CascadeType.PERSIST, CascadeType.MERGE })
  @JoinTable(name = "at",
             joinColumns = @JoinColumn(name = "a_id"),
             inverseJoinColumns = @JoinColumn(name = "b_id"))
  Set<Report> bSet;
}
joinColumn A tablosundaki id alanıdır.
inverseJoinColumn ise B tablosundaki id alanıdır.

B sınıfı şöyle olsun. Ya da şöyle olsun
@Entity
public class B {
  @Column(name = "b_id")
  String id;

  @ManyToMany(mappedBy = "bSet")
  Set<A> aSet;

}
Set yerine list kullanılabilir.

1 yorum: