วันศุกร์ที่ ๒๑ สิงหาคม พ.ศ. ๒๕๕๒

LINQ To SQL Group by multiple columns

วันนี้จะเขียน Linq To SQL เพื่อให้ทำคำสั่งเหมือน

SELECT cocode, arbook, batchdate, batchno,count(*)
FROM arpendingbill
WHERE cocode = 'TGIP' AND arbook = 'NEWAR'
GROUP BY cocode, arbook, batchdate, batchno

โดยให้นำข้อมูลไปใส่ Class ชื่อ ARPendingBatch เขียนเป็น LINQ ดังนี้ครับ


Dim b = From pb In dc.ARPendingBills _
Where pb.COCode = coCode AndAlso pb.ARBook = arBook _
Group By key = New With {pb.COCode, pb.ARBook, pb.BatchDate, pb.BatchNo} _
Into pbGroup = Group _
Select New ARPendingBatch With {.ARBook = key.ARBook, _
.CoCode = key.COCode, .BatchDate = key.BatchDate, _
.BatchNo = key.BatchNo, .BillCount = pbGroup.Count( _
Function(c) c.BatchDate = key.BatchDate AndAlso _
c.BatchNo = key.BatchNo)}


พอลอง debug เพื่อดู SQLCommand ที่มันสร้างขึ้นมาได้แบบนี้ครับ

SELECT ( SELECT COUNT(*) FROM [dbo].[ARPendingBill] AS [t2] WHERE ([t2].[BatchDate] = [t1].[BatchDate]) AND ([t2].[BatchNo] = [t1].[BatchNo]) AND ([t1].[COCode] = [t2].[COCode]) AND ([t1].[ARBook] = [t2].[ARBook]) AND ([t1].[BatchDate] = [t2].[BatchDate]) AND ([t1].[BatchNo] = [t2].[BatchNo]) AND ([t2].[COCode] = @p0) AND ([t2].[ARBook] = @p1) ) AS [BillCount], [t1].[BatchDate], [t1].[BatchNo], [t1].[ARBook], [t1].[COCode] AS [CoCode] FROM ( SELECT [t0].[COCode], [t0].[ARBook], [t0].[BatchDate], [t0].[BatchNo] FROM [dbo].[ARPendingBill] AS [t0] WHERE ([t0].[COCode] = @p0) AND ([t0].[ARBook] = @p1) GROUP BY [t0].[COCode], [t0].[ARBook], [t0].[BatchDate], [t0].[BatchNo] ) AS [t1]

รู้สึกว่ามันช่างเข้าใจยากพิกล ส่วนหนึ่งเป็นเพราะยังไม่ชินด้วยครับ และควรจะต้องไปจัด Layout ใหม่ให้อ่านง่ายๆก่อน แต่ผลลัพท์ได้ออกมาเหมือนกัน

ลองเขียนโดยใช้ Lambda Expression ครับ

Dim b = dc.ARPendingBills.Where( _
Function(a) a.COCode = coCode AndAlso a.ARBook = arBook).GroupBy( _
Function(g) New With {.coCode = g.COCode, .arBook = g.ARBook, _
.batchDate = g.BatchDate, .batchNo = g.BatchNo}).Select( _
Function(c) New ARPendingBatch With {.ARBook = c.Key.arBook, _
.CoCode = c.Key.coCode, .BatchDate = c.Key.batchDate, _
.BatchNo = c.Key.batchNo, .BillCount = c.Count( _
Function(k) k.BatchDate = c.Key.batchDate AndAlso _
k.BatchNo = c.Key.batchNo)})


ได้ผลลัพท์เหมือนกันครับ (ก็แหงละ ลอง debug ดู SQLCommand ก็เหมือนกับที่เขียนด้านบน)

รู้สึกขัดใจกับ SQLCommand ที่ Linq To SQL สร้างให้ ดังนั้นเลยเปลี่ยนมา ExecuteQuery ตรงๆแทน


Dim b = dc.ExecuteQuery(Of ARPendingBatch)( _
"SELECT cocode, arbook, batchdate, batchno, " & _
"BillCount=count(billRecId) " & _
"FROM arpendingbill & _
"WHERE cocode = '" & coCode & "' and arbook = '" & arBook & "' " & _
"GROUP BY cocode, arbook, batchdate, batchno")


มันไม่ Typed Save ครับ แต่ก็มีข้อดีคือ ผมไม่ต้องใช้เวลาเป็นชั่วโมงในการลองเขียน LINQ To SQl แล้ว debug ได้ SQLCommand ที่อ่านยาก และก็ต้อง Test เยอะเพื่อความมั่นใจ ดังนั้นช่วงนี้ถ้าเจอกรณีแบบนี้ก็จะใช้ ExecuteQuery ไปก่อน แล้วพอมีเวลาหัดให้คล่องๆแล้วค่อยกลับมาแก้ครับ (แต่มันก็อ่านยากเหมือนกันนะ programmer ที่ต้องมาแก้โค้ดนี้ภายหลัง ไม่แน่ใจว่าจะชอบแบบไหน ดังนั้นผมเลย Comment เก็บไว้ทั้ง 3 แบบเลย)

ว่าแต่โค้ด Linq To SQL ด้านบน สามารถเขียนได้ง่ายกว่านี้มั๊ยนะ

๓ ความคิดเห็น:

Unknown กล่าวว่า...

แนะนำตัวช่วยเขียน linq
1. http://www.linqpad.net/

2. http://code.msdn.microsoft.com/vlinq/Release/ProjectReleases.aspx?ReleaseId=810

เด็กศรีราชา กล่าวว่า...

SELECT cocode, arbook, batchdate, batchno,count(*)
FROM arpendingbill
WHERE cocode = 'TGIP' AND arbook = 'NEWAR'
GROUP BY cocode, arbook, batchdate, batchno


สั้นๆๆได้ ดังนี้ครับ


dim q = From pb In dc.ARPendingBills _
Where pb.COCode = coCode AndAlso pb.ARBook = arBook _
Group pb.cocode, pb.arbook, pb.batchdate, pb.batchno By _
pb.cocode, pb.arbook, pb.batchdate, pb.batchno into Group
Select Group.Count() , cocode, arbook, batchdate, batchno

jnithi กล่าวว่า...

ขอบคุณคุณ Tor ครับ เดี๋ยวจะลองใช้ดู

ส่วนคุณเด็กศรีราชา ผมลองแล้วมัน error ครับ ตรง
Group pb.cocode, pb.arbook
แต่ก็ขอบคุณครับ เดี๋ยวจะลองอีกที