Full Stack Development with Spring Boot and React (အခန်း ၅)
Published: 2022-12-31 06:13:02

#Table တွေကြားထဲမှ Relationships များ


အခုဒီအခန်းအစ အနေနဲ့ owner ဆိုတဲ့ database table ကို create လုပ်မှာဖြစ်ပြီး car ဆိုတဲ့ table နဲ့ ချိတ်မှာပါ။
owner တစ်ယောက်မှာ ကားအများကြီးရှိ(many) ပြီး car တစ်စီးမှာတော့ owner တစ်ယောက်တည်း(one) ရှိတယ်ဆိုတဲ့ relationship ပါ။
UML diagram အနေနဲ့ ပြရရင် အောက်ပါအတိုင်းဖြစ်ပါတယ်။ 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ors1aiz2b084omhd5rc1.png)



ဒီတော့ ပထမဦးဆုံး owner ဆိုတဲ့ entity ကို ရေးရမယ်။ entity class create လုပ်တဲ့ နည်းကို ပြီးခဲ့တဲ့ အခန်းတွေမှာ ဖေါ်ပြထားခဲ့ပြီးပါပြီ။
ဒါကတော့ owner entity class ရဲ့ code ပါ။

```java
//Owner.java
package com.packt.demo.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Owner {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long ownerid;
	private String firstname, lastname;

	public Owner() {
	}

	public Owner(String firstname, String lastname) {
		super();
		this.firstname = firstname;
		this.lastname = lastname;
	}

	public long getOwnerid() {
		return ownerid;
	}

	public void setOwnerid(long ownerid) {
		this.ownerid = ownerid;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
}
```

Owner entity class create လုပ်ပြီးပြီဆိုရင် OwnerRepository ကို create လုပ်ရမှာ ဖြစ်ပါတယ်။

```java
//OwnerRepository.java

package com.packt.demo.domain;

import org.springframework.data.repository.CrudRepository;

public interface OwnerRepository extends CrudRepository<Owner,Long> {

}
```

Car entity class နဲ့ Owner entity class ကြားထဲမှာ one-to-many relationship ကိုထည့်မယ်ဆိုရင် @OneToMany နဲ့ @ManyToOne annotation တွေကို သုံးကြရမှာဖြစ်ပါတယ်။ car entity class ထဲမှာ foreign key လိုပါတယ်။ ဒီနေရာမှာတော့ private Owner owner ဆိုတဲ့ field ပါ။ getOwner နဲ့ setOwner ဆိုတဲ့ getter setter တွေလည်း ရှိရပါမယ်။ 


ဒီနေရာမှာ ပြောချင်တာကတော့ association တွေအကုန်လုံးလိုလိုမှာ FetchType.LAZY ကို သုံးဖို့ပါ။ အခုလည်း @ManyToOne မှာ FetchType.LAZY ကို သုံးထားတာ တွေ့ရမှာပါ။ toOne မို့လို့ ရေးပေးရတာဖြစ်ပါတယ်။ toMany relationship တွေမှာ FetchType က LAZY default ဖြစ်တဲ့အတွက် မရေးလဲရပါတယ်။ 


lazy stretagy ဆိုတာ owner object ကို database က ယူလိုက်ရင် သူနဲ့ associated ဖြစ်နေတဲ့ car object တွေကို လိုအပ်မှ ယူသုံးနိုင်မှာဖြစ်ပါတယ်။
lazy မဟုတ်ပဲ eager(FetchType.EAGER) ဆိုရင်တော့ owner object ကို ယူလိုက်တာနဲ့  သူနဲ့ ချိတ်ထားတဲ့ car object တွေ ချက်ချင်းအကုန်ပါလာမှာဖြစ်ပါတယ်။


ဒီတော့ အရင်က ရှိနေပြီးသား Car entity class ရဲ့ code မှာ အောက်ပါအတိုင်း ထပ်တိုးလာတာလေးတွေရှိလာမှာပါ။

 ```java
	// Car.java
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "owner")
	private Owner owner;

	// Getter and setter
	public Owner getOwner() {
		return owner;
	}

	public void setOwner(Owner owner) {
		this.owner = owner;
	}
```

Owner entity class ကနေ Car entity ကို @OneToMany နဲ့ လှမ်းချိတ်ကြရမှာပါ။ Owner တစ်ယောက်မှာ Car အများကြီးရှိတာကိုး။ field တစ်ခု ထပ်ထည့်ရမှာဖြစ်ပြီးတော့ field type က List<Car> ဖြစ်ပါတယ်။ Owner တစ်ယောက်မှာ a list of cars တွေရှိနေတယ်ဆိုတဲ့သဘော။ 

getter setter လေးတွေလည်းထည့်လိုက်ပါဦး။

```java
	// Owner.java
	@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
	private List<Car> cars;

	// Getter and setter
	public List<Car> getCars() {
		return cars;
	}

	public void setCars(List<Car> cars) {
		this.cars = cars;
	}	
```

အထက်ဖေါ်ပြပါ code မှာ cascade ဆိုတာ ဆင့်ကဲဖြစ်ပေါ်မှုလို့ပဲ မြန်မာလို ပြန်လို့ရမယ်ထင်တယ်။ ပြောချင်တာကတော့ cascade ကို ALL လို့ထားလိုက်ရင်ဖြစ်မလဲဆိုတာပါ။


တကယ်လို့ owner object(database record တစ်ကြောင်း) တစ်ခု ပျက်သွားရင် သူ ပိုင်တဲ့ car objects (database recordsတွေ) အကုန်လိုက်ပျက်မှာ။ တကယ်လို့ cascade ကို ALL လို့
ရေးထားရင်။ mappedBy="owner" ဆိုတာကတော့ Car class ထဲက owner ဆိုတဲ့ foreign key ကို အသုံးပြုပြီး Owner class က ချိတ်ပါတယ်လို့ ပြောထားတာ။


ဒီလောက်ရောက်ပြီဆိုရင် project ကို run ကြည့်သင့်ပါတယ်။ foreign key ကို create လုပ်မလုပ်ကို console မှာ ကြည့်ကြည့်ပါ။ 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysm67ahyvzcir3wvkuh5.png)



ပြီးရင်တော့ Car entity class ရဲ့ constructor မှာ အောက်ပါအတိုင်း owner ်field ကိုset လုပ်ဖို့ ထည့်ပေးပါ။

```java
	// Car.java constructor
	public Car(String brand, String model, String color, String registerNumber, int yearMade, int price, Owner owner) {
		super();
		this.brand = brand;
		this.model = model;
		this.color = color;
		this.registerNumber = registerNumber;
		this.yearMade = yearMade;
		this.price = price;
		this.owner = owner;
	}


```


ပြီးရင်တော့ CommandLineRunner ကို သုံးပြီး Owner object တွေကို သူ့ repoထဲ save ပြီးတော့ Car object တွေရဲ့ constructor တွေထဲမှာ သူတို့ owner object တွေကို set လုပ်ပြီး Car repo ကို save လိုက်နိုင်ပါပြီ။

```java
//DemoApplication.java 
package com.packt.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import com.packt.demo.domain.Car;
import com.packt.demo.domain.CarRepository;
import com.packt.demo.domain.Owner;
import com.packt.demo.domain.OwnerRepository;

@SpringBootApplication
public class DemoApplication {
// Inject repositories
	@Autowired
	private CarRepository repository;
	@Autowired
	private OwnerRepository orepository;

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@Bean
	CommandLineRunner runner() {
		return args -> {
// Add owner objects and save these to db
			Owner owner1 = new Owner("John", "Johnson");
			Owner owner2 = new Owner("Mary", "Robinson");
			orepository.save(owner1);
			orepository.save(owner2);
// Add car object with link to owners and save these to db.
			Car car = new Car("Ford", "Mustang", "Red", "ADF-1121", 2017, 59000, owner1);
			repository.save(car);
			car = new Car("Nissan", "Leaf", "White", "SSJ-3002", 2014, 29000, owner2);
			repository.save(car);
			car = new Car("Toyota", "Prius", "Silver", "KKO-0212", 2018, 39000, owner2);
			repository.save(car);
		};
	}
}
```

Relationship တွေအကြောင်းပြောတဲ့နေရာမှာ @ManytoMany Relationship ကိုလည်း ချန်ထားလို့ မရပါဘူး။ 

@ManyToMany ကို ဒီနေရာမှာ သဘောပြောရရင် Owner တစ်ယောက်ဟာ ကား အများကြီး ပိုင်နိုင်သလို ကားတစ်စီးမှာ Owner အများကြီး ရှိနေနိုင်တယ်ဆိုတဲ့ ယူဆချက်ကို ယူဆရမှာပါ။ example အနေနဲ့ပြောတာပါ။

 ဒီ example မှာ ခုနက @OneToMany ကို @ManyToMany ဘယ်လိုပြောင်းလို့ရလည်း
ဆိုတာလေ့လာကြည့်ပါ။ many-to-many မှာ List အစား Set ကို သုံးဖို့ အားပေးပါတယ်။ ဒီတော့ Car entity မှာ

```java
	// Car.java
	@ManyToMany(mappedBy = "cars")
	private Set<Owner> owners;

	public Set<Owner> getOwners() {
		return owners;
	}

	public void setOwners(Set<Owner> owners) {
		this.owners = owners;
	}	
```

owner entity ရဲ့ class definition က ဒီလိုဖြစ်သွားပါမယ်။

```java
	// Owner.java
	@ManyToMany(cascade = CascadeType.MERGE)
	@JoinTable(name = "car_owner", joinColumns = { @JoinColumn(name = "ownerid") }, inverseJoinColumns = {
			@JoinColumn(name = "id") })
	private Set<Car> cars = new HashSet<Car>(0);

	public Set<Car> getCars() {
		return cars;
	}

	public void setCars(Set<Car> cars) {
		this.cars = cars;
	}
	
	
	public Owner() {
	}
```

application ကို run လိုက်မယ်ဆိုရင် car နဲ့ owner ကြားထဲမှာ join table တစ်ခု အော်တိုထွက်လာမှာဖြစ်ပါတယ်။ @JoinTable annotation ကိုသုံးပြီး joined table ကို define လုပ်ထားတာကို အထက်ဖေါ်ပြပါ class မှာတွေ့နိုင်ပါတယ်။ 


ပြီးရင် application ကို run ကြည့်ရင် many to many relationship ရဲ့ database structure ကို အောက်ပါအတိုင်းတွေ့ရမှာပါ။

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnyd146q7d4tzm2oax4y.png)