แนวคิดสถานะการ Edit ใน Subform
กระทู้เก่าบอร์ด อ.Yeadram

 2,240   7
URL.หัวข้อ / URL
แนวคิดสถานะการ Edit ใน Subform

เมื่อเรียก Forms หลักมา Edit ผมอ่าน Record มาใส่ Control
ส่วนตารางหลักไม่มีปัญหาอะไร(single Form) แต่ Subform จะอ่านมาพักใน
TempTable เช่นได้ Record ในตารางชั่วคราวดังนี้
AAAA
BBBB
CCC
เป็น DATASHEET

เมื่อ USER แก้ข้อมูล ซึ่งอาจแก้เป็น
AABB
BBZZ
CCC

หรือแก้แบบนี้
AABB
BBBB
CCC
DDDD
RRRR

จะเห็นว่ามีทั้งแก้เฉยๆ และ เพิ่ม Record ใหม่ เมื่อ SAVE
คือ ย้ายจาก ตารางชั่วคราว ไปเก็บใน ตารางจริง แต่เนื่องจากมันเป็นการ EDIT
RECORD เดิม และเพิ่ม RECORD ใหม่ในคราวเดียวกัน แนวคิดของผมเป็นดังนี้
1.ลบ Record ในตารางจริงที่มี ID =
AAAA
BBBB
CCC (ลบทั้งชุดเลยครับ)

2.Insert เข้าตารางจริงด้วยข้อมูล จากตารางชั่วคราวทั้งชุด
ซึ่งก็ไม่มีปัญหาอะไร

แต่ถ้ามี ข้อมูลใน TABLE สัก 200 Record ผมพบว่ามันช้าเหมือนกัน
(ทั้งอ่านเข้ามาพัก ทั้งย้ายออก ทั้ง Clear ตารางชั่วคราวทิ้ง ดูวุ่นวายเมือนกัน)
มีแนวคิดอื่นอีกไหมครับ หรือวิธีการของผม มันคิดมากไป ขอบคุณครับ

7 Reply in this Topic. Dispaly 1 pages and you are on page number 1

1 @R04423
เคยเห็นเขาใช้วิธี สร้างเงื่อนไขให้ sub form เช่นเลือกข้อมูลที่คิดว่ามันต้องใช้จริงๆหรือต้องปรับปรุงจริงมาแสดง ส่วนอื่นไม่เอา ตย.ใส่เงื่อนไข between..And.. เพื่อเลือกช่วงข้อมูลเฉพาะปีนั้นๆ ที่ต้องการทำงานกับมันมาพอ
2 @R04425
คำสั่งที่ใช้ก็อปปี้เรคอร์ด , ลบเรคอร์ด คุณใช้ยังไงครับ
3 @R04441
คิดว่าเร็วขึ้นแล้วครับด้วยวิธีนี้

Private Sub Save_Click()
Dim k As Integer 'เก็บค่า K ไว้ตรวจสอบสถานะ RS
k = RS.EditMode
Me.T0.SetFocus   

Dim i As Integer 'Update ตารางหลักก่อน
i = 0
Do Until i > 50
On Error Resume Next
RS.Fields(i) = Me("T" & i)
i = i + 1
Loop
RS.Update

Dim SqlAdd As String   
SqlAdd = "INSERT INTO Sun SELECT SunTemp .* FROM SunTemp"

If k = dbEditAdd Then   'ถ้า ADD ให้ บวกเพิ่มได้เลย
DoCmd.RunSQL SqlAdd
End If

If k = dbEditInProgress Then 'ถ้า EDIT

Dim SqlDelCId As String   'ลบข้อมูลออกก่อน
SqlDelCId = " DELETE Sun.* FROM Sun "
SqlDelCId = SqlDelCId & " WHERE sun.id_MOM = "
SqlDelCId = SqlDelCId & " " & Forms("FormC").T0
DoCmd.RunSQL SqlDelCId

DoCmd.RunSQL SqlAdd 'และเพิ่มเข้าไปจากตาราง ชั่วคราว

End If

Dim SqlDelCB As String    'เคลียตารางชั่วคราวทิ้ง
SqlDelCB = " DELETE SunTemp.* FROM SunTemp;"
DoCmd.RunSQL SqlDelCB

[FormD].Form.Requery ' Subform Requery


Call SaveCancel(False)
Call Opera(True)
Call Clear

Forms("FormC").ADD.SetFocus 'เรียก ADD เพื่อเตรียม addnew
SendKeys " ", True

End Sub

อย่างไรก็ตามผมยังอยากให้อาจารย์ วิเคราะ วิจารย์ให้อยู่ดีครับ
ส่วนเรื่องการอ่าน Record(Copy Record) มา ผมก็ใช้ลักษณะเดียวกัน
คือให้ SQL เช่น

Dim SqlAdd As String
SqlAdd = "INSERT INTO SunTemp SELECT Sun.* FROM Sun"
SqlAdd = SqlAdd & " WHERE sun.id_MOM = "
SqlAdd = SqlAdd & " " & Forms("FormB").T0
DoCmd.RunSQL SqlAdd

และสิ่งสำคัญที่อยากได้มากคือ เคยถามอาจารย์ว่า ถ้าเกิด ไฟดับช่วงที่ SAVE
แล้ว มีการโอนถ่ายข้อมูลไม่หมด (Roll Back) จะเขียนอย่างไรครับ เห็นอาจารย์
เคยเขีย Begine อะไรทำนองนี้ ถ้าของผม ที่เขียนมาจะวางไว้อย่างไรตรงไหนบ้างครับ
4 @R04444
- ดูแล้วก็แปลกๆ คือไม่ทราบว่า RS ถูกกำหนดมาจากที่ไหน แล้วทำไมถึงใช้ RS.EditMode เป็นตัวทดสอบว่าเป็นการ เพิ่ม หรือ แก้ไข เรคอร์ด

- การทำ transaction ให้เริ่มด้วย method .BeginTrans ก่อนบรรทัดที่จะสั่งให้เริ่มปรับปรุงเรคอร์ด และจบด้วย method .CommitTrans หลังบรรทัดสุดท้ายที่ปรับปรุงเรคอร์ด   ถ้าต้องการยกเลิก Transaction ให้สั่งด้วย method .Rollback (หรือ .RollbackTrans ถ้าเป็น ADO) ADO และ DAO จะใช้ method นี้กับ object คนละตัว DAO จะใช้กับ DBEngine object หรือ WorkSpace object ในขณะที่ ADO จะใช้กับ Connection object   ลองหาดู ตย.ใน Help File ครับ
5 @R04462
ถ้าจะทำให้ง่ายๆผมว่าลองแบบนี้ดีไหม
1. ใน form main ควรจะมี combobox สักตัวแล้วเขียน code ใน Afterupdate event เป็น
Me.ชื่อSubform.Form.Recordsource="SELECT Fieldที่ต้องการ FROM Table WHERE Fieldที่ใช้อ้างอิง = Forms!ชื่อFormmain.ชื่อCombobox;"

2. ใน subform (คาดว่าคงเป็น Datasheet view?) เอาแบบง่ายๆเข้าไปอีกนะครับ สร้างปุ่ม Delete ไว้ด้วย แล้วเขียน code ใน Onclick event แบบนี้
DoCmd.RunCommand acCmdDeleteRecord

3. คราวนี้จะแก้ไข จะเพิ่ม จะลบ ก็ทำได้หมดละครับ ไม่ต้องสร้าง temp table sinvเขียน code insert delete อะไรให้วุ่นวาย

4. ส่วนเรื่องจะใช้ commit rollback อะไรนั่นคงต้องเป็นแบบที่คุณสันติสุขว่าไว้ละครับ
6 @R04852
ขอต่อเรื่องประเด็น begintrans ได้ Code ลองแล้วว่า OK ประมาณนี้
Private Sub Save_Click()
On Error GoTo Err:
DBEngine.BeginTrans '**************************
Dim k As Integer
k = Rs.EditMode

Me.T0.SetFocus   
Dim i As Integer
i = 0
Do Until i > 2
On Error Resume Next
Rs.Fields(i) = Me("T" & i)
i = i + 1
Loop
Rs.Update

Dim SqlAdd As String   
SqlAdd = "INSERT INTO Sun SELECT SunTemp .* FROM SunTemp"

If k = dbEditAdd Then
DoCmd.RunSQL SqlAdd
End If

If k = dbEditInProgress Then
Dim SqlDelCId As String
SqlDelCId = " DELETE Sun.* FROM Sun "
SqlDelCId = SqlDelCId & " WHERE sun.id_MOM = "
SqlDelCId = SqlDelCId & " " & "'" & Forms("FormC").T0 & "'"
DoCmd.RunSQL SqlDelCId

DoCmd.RunSQL SqlAdd
End If

Dim SqlDelCB As String
SqlDelCB = " DELETE SunTemp.* FROM SunTemp;"
DoCmd.RunSQL SqlDelCB

Call SaveCancel(False)
Call Opera(True)
Call Clear
DBEngine.CommitTrans   '**************************

On Error Resume Next
[FormD].Form.Requery

Forms("FormC").ADD.SetFocus
SendKeys " ", True
Exit Sub

Err:
If Err.Number <> 0 Then
     MsgBox Err.Number & " " & Err.Description
    DBEngine.Rollback   '**************************
End If

End Sub

1.ตรงส่วน********************ที่ mark ไว้ ประมาณนี้หรือเปล่าครับ
2.ถ้าผมจะทดสอบ Code นี้ว่าถูก(มีการ RollBack จริง) จะทดสอบอย่างไรดีครับ
(สมมุติเหตุการไฟดับ...แต่หวังว่าคงไม่ต้องถอดปร๊กจริงนะครับ)
3.ในประเด็นของคุณ Nova คิดว่าน่าสนใจครับ ที่ไม่ต้องสร้าง TempTable
แต่นึกภาพไม่ออกจริงๆ ครับ ถ้าได้ตัวอย่างคร่าวๆ ก็ดีครับ(ถ้าให้ได้)ฝาก Email ของ Board ก็ได้ครับ
7 @R04885
1) ครับ ก็อย่างนั้นแหล่ะ แต่ว่าการ Rollback โดยไม่มีการทำ BeginTrans มาก่อนจะทำให้เกิด runtime error ได้ ดังนั้นจึงมักใช้ตัวแปรตัวนึงเพื่อเป็น flag บอกว่าได้สั่ง BeginTrans ไปแล้วหรือยัง ก็จะเป็นลักษณะ

Dim Flag As Boolean
...
...
DBEngine.BeginTrans : Flag = True
...
DBEngine.CommitTrans : Flag = False
...
DBEngine.Rollback : Flag = False
...
...
Err:
If Err.Number <> 0 Then
    MsgBox Err.Number & " " & Err.Description
    If Flag then DBEngine.Rollback: Flag = False
End If

2) จะทดสอบก็ทำให้มันเกิด error ตรงบรรทัดไหนสักบรรทัดที่อยู่ระหว่าง BeginTrans และ CommitTrans ด้วยการเขียนคำสั่ง Err.Raise 0 แทรกเข้าไปครับ คำสั่ง Err.Raise รหัสข้อผิดพลาด เป็นการสั่งให้เกิด error ตามรหัสที่ว่านั้นครับ
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.3748s