Servis masası

Şimdi başka bir yaygın duruma bakalım - çoktan çoğa. Görevler ve çalışanlar arasında çoktan çoğa bir ilişkimiz olduğunu düşünelim :

  • Çalışan tablosundaki bir çalışan, görev tablosundan birçok görevi yapabilir.
  • Görev tablosundaki bir görev, birkaç çalışana atanabilir.

Varlıklar arasındaki bu ilişkiye çoktan çoğa denir. Ve bunu SQL seviyesinde uygulamak için ek bir servis tablosuna ihtiyacımız var. Buna örneğin, çalışan_görevi diyelim.

Çalışan_görevi tablosu yalnızca iki sütun içerecektir:

  • Çalışan kimliği
  • görev_kimliği

Belirli bir kullanıcıya belirli bir görev atadığımız her seferde, bu tabloya yeni bir satır eklenecektir. Örnek:

Çalışan kimliği görev_kimliği
1 1
1 2
2 3

Pekala, görev tablosu çalışan_kimliği sütununu kaybetmeli . Yalnızca görev yalnızca bir çalışana atanabiliyorsa mantıklıdır. Görev birden fazla çalışana atanabiliyorsa, bu bilgi çalışan_görevi hizmet tablosunda saklanmalıdır .

Tablo Düzeyinde İlişki

Yeni tablolarımız şöyle görünecek:

İD isim meslek maaş yaş katılmak_tarihi
1 İvanov İvan Programcı 100000 25 2012-06-30
2 Petrov Petr Programcı 80000 23 2013-08-12
3 İvanov Sergey test cihazı 40000 otuz 2014-01-01
4 Rabinovich Moisha Müdür 200000 35 2015-05-12
5 Kirienko Anastasia Ofis Yöneticisi 40000 25 2015-10-10
6 Vaska Kedi 1000 3 2018-11-11

Çalışan tablosu ( değişmedi ) :

Bu tablo aşağıdaki sütunlara sahiptir:

  • kimlik INT
  • isim VARCHAR
  • meslek _
  • maaş INT
  • yaş INT
  • katılım_tarihi DATE

Ve görev tablosu şu şekilde görünüyor , staff_id sütununu kaybetti (kırmızı ile işaretlenmiş):

İD çalışan kimliği isim son teslim tarihi
1 1 Ön uçtaki bir hatayı düzeltin 2022-06-01
2 2 Arka uçtaki bir hatayı düzeltin 2022-06-15
3 5 kahve satın al 2022-07-01
4 5 kahve satın al 2022-08-01
5 5 kahve satın al 2022-09-01
6 (HÜKÜMSÜZ) ofisi temizle (HÜKÜMSÜZ)
7 4 Hayatın tadını çıkar (HÜKÜMSÜZ)
8 6 Hayatın tadını çıkar (HÜKÜMSÜZ)

Bu tabloda artık yalnızca 3 sütun var:

  • id - benzersiz görev numarası (ve tablodaki satırlar)
  • çalışan_kimliği - (kaldırıldı)
  • ad - görevin adı ve açıklaması
  • son tarih - görevin tamamlanması gereken süre

Ayrıca , çalışan_kimliği verilerinin görev tablosundan taşındığı bir çalışan_task hizmet tablosuna da sahibiz :

Çalışan kimliği görev_kimliği
1 1
2 2
5 3
5 4
5 5
(HÜKÜMSÜZ) 6
4 7
6 8

Silinen sütunu geçici olarak görev tablosuna kaydettim, böylece buradaki verilerin çalışan_görev tablosuna taşındığını görebilirsiniz.

Bir diğer önemli nokta ise staff_task tablosundaki kırmızı çizgi olan "(NULL) 6" dır. Çalışan_görevi tablosunda olmayacağı için kırmızıyla işaretledim .

Görev 7, kullanıcı 4'e atanmışsa, çalışan_görev tablosunda bir satır (4, 7) olmalıdır.

Görev 6 kimseye atanmamışsa, çalışan_görev tablosunda bunun için hiçbir kayıt olmayacaktır. İşte bu tabloların son sürümleri şöyle görünecek:

görev tablosu :

İD isim son teslim tarihi
1 Ön uçtaki bir hatayı düzeltin 2022-06-01
2 Arka uçtaki bir hatayı düzeltin 2022-06-15
3 kahve satın al 2022-07-01
4 kahve satın al 2022-08-01
5 kahve satın al 2022-09-01
6 ofisi temizle (HÜKÜMSÜZ)
7 Hayatın tadını çıkar (HÜKÜMSÜZ)
8 Hayatın tadını çıkar (HÜKÜMSÜZ)

çalışan_görev tablosu:

Çalışan kimliği görev_kimliği
1 1
2 2
5 3
5 4
5 5
4 7
6 8

Java sınıfı düzeyinde iletişim

Ancak Entity sınıfları seviyesindeki iletişim ile tam bir düzene sahibiz. İyi haberle başlayalım.

İlk olarak, Hibernate , çoktan çoğa tablo ilişkisini iyi bir şekilde tanımlamanıza izin veren özel bir @ManyToMany ek açıklamasına sahiptir.

İkincisi, iki Entity sınıfı bizim için hala yeterli. Servis tablosu için bir sınıfa ihtiyacımız yok.

İşte sınıflarımızın nasıl görüneceği. Özgün biçiminde Çalışan sınıfı :

@Entity
@Table(name="user")
class Employee {
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @Column(name="occupation")
   public String occupation;

   @Column(name="salary")
   public Integer salary;

   @Column(name="join_date")
   public Date join;
}

Ve orijinal haliyle, EmployeeTask sınıfı:

@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String description;

   @Column(name="deadline")
   public Date deadline;
}

@ManyToMany notu

Örneklerdeki mevcut alanları çıkaracağım, ancak yenilerini ekleyeceğim. İşte nasıl görünecekleri. Çalışan sınıfı :

@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;

   @ManyToMany(cascade = CascadeType.ALL)
   @JoinTable(name="employee_task",
	       joinColumns=  @JoinColumn(name="employee_id", referencedColumnName="id"),
           inverseJoinColumns= @JoinColumn(name="task_id", referencedColumnName="id") )
   private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();

}

Ve EmployeeTask sınıfı :

@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;

   @ManyToMany(cascade = CascadeType.ALL)
   @JoinTable(name="employee_task",
       	joinColumns=  @JoinColumn(name="task_id", referencedColumnName="id"),
       	inverseJoinColumns= @JoinColumn(name=" employee_id", referencedColumnName="id") )
   private Set<Employee> employees = new HashSet<Employee>();

}

Her şey karmaşık gibi görünüyor, ama aslında her şey basit.

İlk olarak, staff_task hizmet tablosunu açıklayan @JoinTable notunu (@JoinColumn ile karıştırılmamalıdır) kullanır .

İkinci olarak, staff_task tablosunun task_id sütununun görev tablosunun id sütununa atıfta bulunduğunu açıklar.

Üçüncüsü, çalışan_görev tablosunun çalışan_kimliği sütununun çalışan tablosunun kimlik sütununa atıfta bulunduğunu söylüyor.

Aslında ek açıklamalar yardımıyla, staff_task tablosunda hangi verilerin bulunduğunu ve Hibernate'in bunu nasıl yorumlaması gerektiğini açıkladık.

Ancak artık herhangi bir çalışana çok kolay bir şekilde görev ekleyebilir (ve silebiliriz). Ayrıca herhangi bir göreve herhangi bir sanatçı ekleyin.

İstek örnekleri

Bu ManyToMany alanlarının nasıl çalıştığını daha iyi anlamak için birkaç ilginç sorgu yazalım. Ve tam olarak beklendiği gibi çalışıyorlar.

İlk olarak, yönetmenin daha önce bir görev alanı olduğu için eski kodumuz değişmeden çalışacaktır:

EmployeeTask task1 = new EmployeeTask();
task1.description = "Do Something Important";
session.persist(task1);

EmployeeTask task2 = new EmployeeTask();
task2.description = "Nothing to do";
session.persist(task2);
session.flush();

Employee director = session.find(Employee.class, 4);
director.tasks.add(task1);
director.tasks.add(task2);

session.update(director);
session.flush();

İkinci olarak, bir göreve başka bir oyuncu atamak istiyorsak, bunu yapmak daha da kolaydır:

Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);

session.update(task);
session.flush();

Önemli! Bu talebin yerine getirilmesi sonucunda, sadece görevin bir yürütücü-yönetmeni olmayacak, aynı zamanda yönetmenin de 101 numaralı görevi olacaktır.

İlk olarak, çalışan_görev tablosundaki yönetici ile görev arasındaki ilişki hakkındaki gerçek bir dizi olarak saklanacaktır: (4,101).

İkincisi, @ManyToMany ek açıklamalarıyla işaretlenen alanlar proxy nesneleridir ve bunlara erişildiğinde her zaman bir veritabanı sorgusu yürütülür.

Dolayısıyla, bir çalışana bir görev eklerseniz ve çalışanla ilgili bilgileri veritabanına kaydederseniz, bundan sonra görevin yürütücüler listesinde yeni bir yürütücü olacaktır.