หลังจากที่ผ่านมาได้พูดถึงการจัดการ GORM Relationship แบบ One-to-Many กันแล้วมา entry นี้จะมาพูดถึงการจัดการความสัมพันธ์แบบ many-to-many กันบ้าง

เริ่มกันเลย ……..

ในการจัดการความสัมพันธ์แบบนี้ โดยทั่วไปนั้นจะสร้าง table กลางขึ้นมาเพื่อเชื่อมความสัมพันธ์กันดังรูป

ซึ่งจะมองได้ว่าเป็นมีความสัมพันธ์ขึ้นดังนี้
BookWriter –> Book
BookWriter –> Writer

เมื่อมาจัดการความสัมพันธ์ลักษณะนี้ใน GORM สามารถทำได้ง่าย โดยจุดสำคัญอยู่ที่ domain class : BookWriter จะเป็นตัวเชื่อมความสัมพันธ์ของ Book และ Writer ดังนี้

Book.groovy

class Book {
	String name
}

Writer.groovy

class Writer {
	String name
}

BookWriter.groovy

import Writer
class BookWriter {
	static belongsTo = [ book:Book, writer:Writer ]
}

คำอธิบาย
static belongsTo = [ book:Book, writer:Writer ] จะใช้กำหนดเจ้าของความสัมพันธ์นี้ ซึ่งก็คือ Book และ Writer

ลองมาสร้างข้อมูลกัน

//1. สร้าง Book
def b = new Book( name:"Book Name" )
b.save()

//2. สร้าง Writer
def w = new Writer( name:"Writer Name" )
w.save()

//3. สร้างความสัมพันธ์ของ Book และ Writer
def bw = new BookWriter( book:b, writer:w )
bw.save()

ตัวอย่างการดึงข้อมูล ซึ่งจะใช้ domain class BookWriter เป็นหลักดังนี้

println BookWriter.get(1).book.name
println BookWriter.get(1).writer.name

หรืออาจจะใช้ Criteria มาช่วย ดังนี้

def bw = BookWriter.createCriteria()
def results = bw.list {
    book {
        like("name", "Book%")
    }
    writer {
        like("name", "Writer%")
    }
}
println results

จะเห็นว่าการใช้งาน Criteria ทำให้ชีวิตง่ายขึ้นมาอีก เนื่องจากสามารถใส่เงื่อนไขต่างๆ เป็น closure ได้เลย หรือถ้าใครถนัด Hibernate มากกว่าอาจ Hibernate Query Language [ HQL ] ได้

จากตัวอย่างด้านบนนั้นใน Book และ Writer จะไม่รู้เลยว่ามีความสัมพันธ์อะไรบ้าง ยกเว้นจะไปดูใน BookWriter แต่เราสามารถกำหนดเพิ่มเพื่อให้ Book และ Writer โดยการเพิ่ม code ดังนี้ไปยังทั้ง 2 domain classes

static hasMany = [bookWriters: BookWriter]  //  สามารถทำ cascade delete ได้

วิธีการดังกล่าวนั้นเป็นวิธีการที่ make sense ในโลกของ RDBMS แต่ในโลกของ Object Oriented มันรู้สึกแปลกๆ คุณว่าไหม ??? มันน่าจะมีวิธีการที่เหมาะสมกับโลกของ Object Oriented สิ

ดังนั้น GORM จึงขอเสนออีกหนึ่งวิธีดังนี้

โดยการใช้ hasMany ในการกำหนดความสัมพันธ์แบบ one-to-many ทั้งสองฝั่ง

ดังนั้นสามารถกำหนดใน GORM ได้ดังนี้
Book.groovy

class Book{
	static hasMany = [ writers : Writer ]   // ชนิดของ writers คือ java.util.Set   

	String name
}

Writer.groovy

class Writer {
	// กำหนดให้ Book เป็นเจ้าของความสัมพันธ์ [ Unidirection ] เพื่อป้องกันการ cascade delete
	static belongsTo = Book 

static hasMany = [ books: Book ]   // ชนิดของ books คือ java.util.Set 

	String name
}

ตัวอย่างการสร้าง

def book = new Book( name:"Book Name" )
book.writers = [
		new Writer( name : "Writer Name 1"),
		new Writer( name : "Writer Name 2")
                     ]
book.save()

จะเห็นได้ว่าสามารถสร้างข้อมูลได้อย่างง่ายดาย แต่ในทางกลับกันไม่สามารถทำการสร้างแบบ reverse ได้ ดังตัวอย่าง

def writer = new Writer( name:"Writer Name" );
writer.books = [
		new Book( name:"Book Name 1" ),
		new Book( name:"Book Name 2" )
	       ]
writer.save();

ซึ่งข้อจำกัดนี้จะเหมือนกับ Hibernate ซึ่งเป็น core ของ GORM [ สามารถจัดการความสัมพันธ์แบบ many-to-many ได้เพียงด้านเดียวเท่านั้น ]

ในการลบข้อมูลในความสัมพันธ์แบบนี้จะไม่ทำงานลบข้อมูลของ Writer ด้วย เนื่องจากสามารถมีความสัมพันธ์กับ Book อื่นๆได้

def  book= Book.get(1);
book.delete();

นี่ก็คือการจัดการความสัมพันธ์แบบ many-to-many ใน GORM ครับ

ง่ายหรือเปล่าครับ ????

Web Reference
http://grails.org/doc/1.0.x/

Tags: , ,

2 Responses to “การจัดการ GORM Relationship แบบ Many-to-Many”

Trackbacks/Pingbacks

  1. เร็วส์ หกสิบหก » สนุกกับ Active Record: การเชื่อมโยงแบบ many-to-many (2)
  2. สนุกกับ Active Record: การเชื่อมโยงแบบ many-to-many (2) « Jittat

Leave a Reply