หากมีคำถาม ขอให้ไปโพสต์ลง เว็บบอร์ดจีทูจีเน็ตดอตคอม ตัวใหม่แทนน่ะครับ

หรือติดต่อเข้ามาทาง Inbox ที่ เฟซบุ๊ค ผมครับ

หน้าหลัก
ข่าวสาร - บทความ ทั้งหมด
VB 6/VB.Net
ASP/ASP.Net
จับฉ่ายคอมพิวเตอร์
เรียนรู้ผ่าน Flash Movie
บทความที่มีผู้ตอบล่าสุด  
 RSS Feeds
 ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...   Download โปรแกรม RSS Reader

Forum - www.g2gnet.com
Webmaster - www.g2gnet.com
Visitors - Session views
 4 7 6 6 2 2 7

7 ธันวาคม พ.ศ.2549
255 Users On-Line.
Visitors - Page views
 7 9 9 1 2 3 0
1 กุมภาพันธ์ พ.ศ.2551

Google   
เว็บ g2gnet.com
ขนาดตัวอักษร:  

VB6 กับการใช้งาน Data Control ภาค 3 (การแก้ไขข้อมูล)

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 19/10/2553   เวลา: 13:03
(อ่าน : 22368) 
การฝึกเขียนโปรแกรม มันก็ไม่จำเป็นที่จะต้องมีอาชีพเป็นโปรแกรมเมอร์แต่เพียงอย่างเดียว หรอกน่ะครับ ... สายงานด้านอื่นๆ ก็สามารถนำไปใช้ในการเขียนโปรแกรมขนาดเล็กๆ เอาไว้ใช้งานในองค์กรก็ได้ แต่ปัญหาหลักๆสำหรับคนที่เริ่มฝึกเขียนโปรแกรมระบบฐานข้อมูล คือ ไม่เข้าใจขั้นตอนของการทำงาน หรือ ว่าง่ายๆ เรียนรู้อย่างไม่ค่อยเป็นระบบ (บางคนอาจจะพะวงแต่การเขียน ER-Model ก็ได้มั้ง เอิ๊กๆๆๆๆ) ... ในงานเขียนโปรแกรมระบบฐานข้อมูล สิ่งที่สำคัญอันดับแรกเลย (ไม่นับการออกแบบตารางข้อมูล)
    ต้องสามารถทำการค้นคืนข้อมูล (Retrieve) ออกมาให้ได้ เพื่ออะไรล่ะ ...
  • เพิ่มข้อมูล ... เช่น หากค้นหารายการสินค้าไม่พบ ผู้ใช้งานก็ต้องทำการเพิ่มข้อมูลเข้าไปใหม่
      สาระสำคัญ คือ
    • สร้างค่า Primary Key ใหม่ ที่ต้องไม่ไปซ้ำกับของเดิม (โดยเด็ดขาด)
    • ตรวจสอบรหัสพวก Code หรือ ID เช่น รหัสสินค้า รหัสลูกค้า จะต้องไม่ไปซ้ำกับของเดิม ซึ่งสามารถทำได้ 2 แบบ คือ สร้างรหัสอัตโนมัติ หรือ ให้ผู้ใช้ป้อนเอง (พวกนี้ไม่ได้เป็น Primary Key น่ะครับ ... เอาไว้อ้างถึงสำหรับผู้ใช้งาน)
  • แก้ไขข้อมูล
      สาระสำคัญ คือ
    • เก็บค่า Primary Key เดิมไว้เพื่อใช้อ้างอิงในการ Update ข้อมูล
    • ตรวจสอบรหัส เช่น รหัสสินค้า ต้องไม่ไปซ้ำกับของตัวอื่นที่มีอยู่แล้ว (เผื่อผู้ใช้อาจจะเปลี่ยนแปลงค่า) ... (อ่านเทคนิควิธีการเขียนโค้ดได้ ... ที่นี่)
  • ลบข้อมูล ...
      สาระสำคัญ คือ
    • ต้องตรวจสอบความสัมพันธ์ระหว่างตารางข้อมูลก่อน เช่น เกิดการขายสินค้า A ออกไปแล้ว ผู้ใช้จะต้องไม่สามารถลบรายการสินค้า A ออกจากระบบได้ ไม่งั้นรายการขายจะเกิด Error หรือ ไม่สามารถตรวจสอบข้อมูลย้อนหลังได้

    ไม่ว่าจะเขียนโปรแกรมระบบงานฐานข้อมูลใดๆ (หรือ ใช้ภาษาอะไรก็ตามที) หลักการนี้ไม่ได้เปลี่ยนแปลงไปเลย ... สำหรับ Visual Basic ... มันจะเรียงลำดับตามเหตุการณ์ (Events) ว่าเกิดอะไรขึ้น แล้วจะสั่งให้มันไปทำอะไร หรือ Driven ... Events ที่ว่ามาก็คือ โปรแกรมย่อยนั่นเองแหละครับ ดังนั้นจึงมีความจำเป็นที่เราจะต้องทำความเข้าใจ เรื่องของโปรแกรมย่อยให้ดีก่อนด้วย ... (อ่านรายละเอียดเพิ่มเติมได้ ... ที่นี่)
ดาวน์โหลด Source Code สำหรับผู้ใช้งาน Visual Basic 6
ดาวน์โหลด Source Code สำหรับ MS Visual Basic 6.0 - Service Pack 6
 ดาวน์โหลด Visual Basic 6.0 SP5: Run-Time Redistribution Pack
 ดาวน์โหลด Microsoft Data Access Object (MDAC) และ Jet 4.0 Update
 ดาวน์โหลด Microsoft Visual Basic Service Pack 6
ข้อมูลเพิ่มเติม
VB6 กับการใช้งาน Data Control ภาค 1 ปฐมบท (Design Time ก็ทำงานได้)
VB6 กับการใช้งาน Data Control ภาค 2 (ลูกผสม Design และ Run Time)
VB6 กับการใช้งาน Data Control ภาค 4 (โค้ด Run Time)
VB6 กับการใช้งาน Data Control ภาค 5 (ฉบับตราเด็กสมบูรณ์)
วิดีโอสอนขั้นตอนการ Debug Program ด้วย MS Visual Basic 6.0
วิดีโอสอนขั้นตอนการออกแบบความสัมพันธ์ระหว่างตารางแบบ One To One
คำเตือน ... Warning

คุณจะรันโปรแกรมไม่ได้ หากคุณไม่เริ่มต้นการผูกไฟล์ข้อมูลให้กับ ADO Data Control เสียก่อน
ดูรายละเอียดขั้นตอนของการเชื่อมต่อฐานข้อมูลแบบ Design Time


การออกแบบ - Design Time (รายละเอียดต่างๆไปดูที่ภาค 1 ... คลิ๊กที่นี่)
คุณสมบัติที่สำคัญของ DataGrid ... สังเกตน่ะครับว่าใน VB ค่า True = -1 ส่วน False = 0
AllowAddNew = 0 'False
AllowDelete = 0 'False
AllowUpdate = 0 'False
AllowArrows = -1 'True
ColumnHeaders = -1 'True
FormatLocked = -1 'True


หากนำ Query ในตัวอย่างจาก MS Access ของผมไปใช้ ต้องตัดหลักแสดง ProvinceFK ออกไปก่อนด้วย
Project --> Components

ต้องเลือก DataList Control เข้ามาด้วย ซึ่ง Control ตัวนี้จะประกอบไปด้วย DataList กับ DataCombo (จะใช้ตัวหลัง)

จากฟอร์มการแก้ไขข้อมูล frmEditData.frm จะต้องทำการผูกข้อมูลเข้าไปที่ ADO Data Control ก่อน
ดูรายละเอียดขั้นตอนของการเชื่อมต่อฐานข้อมูลแบบ Design Time

คุณสมบัติที่สำคัญของ DataCombo (กำหนดขณะออกแบบหน้าจอ - Design Time)
DataField = "ProvinceName"
DataSource = "Adodc2"
Style = 2
ListField = "ProvinceName"
BoundColumn = ""
Text = "DataCombo1"


สำหรับการกำหนด RecordSource ให้กับรายละเอียดของลูกค้า
ใช้ adCmdTable และเลือก CustomerProvince ซึ่งตัวนี้ คือ Query ตัวอย่างที่ผมทำไว้ใน DataBase


สำหรับการกำหนด RecordSource ให้กับ DataCombo1 ... ซึ่งจะแสดงรายชื่อจังหวัด (ใช้ Adodc2)


ขณะที่รันโปรแกรม (Run Time) - สามารถทดสอบเลือกรายการเดินหน้า ถอยหลังใน Adodc2 ซึ่งจะผูกข้อมูลเข้ากับ DataCombo1


ผมไม่ได้ผูกข้อมูลระหว่าง Adodc1 เข้ากับ TextBox น่ะครับ ... ลองคิดดูว่าทำไม
โค้ดจากฟอร์ม frmEditData.frm

Option Explicit

' #####################################################
' ประกาศตัวแปรที่เห็นได้หมดในฟอร์มนี้ ... เพราะต้องนำไปใช้ซ้ำๆกัน ในหลายๆโปรแกรมย่อย
' ซึ่งเราจะประกาศ (Declare) มันครั้งเดียวก็เพียงพอแล้วขอรับ ...
' #####################################################

' ตัวแปรเพื่อเก็บค่า String ในการทำ SQL Statement
Dim Statement As String

' ตัวแปรเพื่อรับค่า CustomerPK เข้ามาจากฟอร์มหลัก (DataGrid)
' เพราะต้องนำค่านี้ไปใช้งานตอน ...
' 1. แสดงผลข้อมูล (อยู่ที่ Form_Load)
' 2. บันทึกข้อมูล (ในโปรแกรมย่อย SaveData) อีกด้วย
' ความจริงแล้ว สำหรับค่า Primary Key เราอ้างถึงฟอร์มหลักที่เรียกมาก็ได้
' เช่น frmDataControlRetrieve.DataGrid1.Text
' แต่ที่ผมแยกให้เห็น เพื่อจะได้ไม่งง ... เลยตั้งชื่อมันซ่ะเต็มยศเลย 55555+
' ที่จริงแล้วผมมีเทคนิคที่ผมใช้อีกแบบ ... กลับไปหาดูในบทความเก่าๆของผมด้วยล่ะกันครับ
Dim CustomerPrimaryKey As Long

' #####################################################
' เริ่มต้นการแสดงรายละเอียดของลูกค้า ตามค่า Primary Key จากฟอร์มหลัก
' #####################################################
Private Sub Form_Load()
    
    ' รับค่า CustomerPK ที่เราซ่อนเอาไว้ จากหลักแรก (Index = 0) มาจากฟอร์มหลัก
    ' ก่อนจะมาถึงฟอร์มนี้ เรากำหนดให้อ่านหลัก 0 ของ DataGrid มาก่อนแล้วล่วงหน้า
    ' หากเอาแบบให้แน่ใจก็กำหนดใหม่ได้ โดยการอ้างถึงฟอร์มหลักโดยตรง
    frmDataControlRetrieve.DataGrid1.Col = 0
    CustomerPrimaryKey = frmDataControlRetrieve.DataGrid1.Text
    
    ' ส่วนนี้จริงๆแล้ว ต้องแยกออกเป็นโปรแกรมย่อย เพราะต้องมีการทดสอบก่อนว่าเป็นการเพิ่ม หรือ แก้ไขข้อมูล
    ' หากเป็นการเพิ่มข้อมูลใหม่ ก็จะเคลียร์ค่า Control ต่างๆเพื่อเริ่มต้นการป้อนข้อมูลใหม่
    ' หากเป็นการแก้ไข ก็จะต้องทำการแสดงผลข้อมูลเดิมขึ้นมา ... นี่แหละคือการออกแบบเป็นขั้นเป็นตอน
    ' ทำ Query เพื่อทำการค้นหาข้อมูล
    Statement = "SELECT tblCustomer.CustomerPK, tblCustomer.CustomerCode, " & _
                    " tblCustomer.CustomerName, tblCustomer.Address, tblCustomer.Amphur, " & _
                    " tblCustomer.ProvinceFK, tblProvince.ProvinceName, tblCustomer.PostCode " & _
                    " FROM tblCustomer INNER JOIN tblProvince ON " & _
                    " tblCustomer.ProvinceFK = tblProvince.ProvincePK " & _
                    " WHERE " & _
                    " [CustomerPK] = " & CustomerPrimaryKey & _
                    " ORDER BY CustomerPK "
    
    With Adodc1
    
        ' ผูกข้อมูลตาม Query ที่กำหนดให้กับ ADO Data Control ใหม่อีกครั้ง
        .RecordSource = Statement
        
        ' สั่งทำงานตามคำสั่ง SQL (Query) ... กรณีที่ Design Time ไม่ได้ตั้งค่าเอาไว้ล่วงหน้า
        .CommandType = adCmdText
        
        ' สามารถอ่านจำนวน Record ได้ ... ไปกำหนดตอน Design Time เอาก็ได้ครั้งเดียว
        .CursorLocation = adUseClient
        
        ' อ่านเดินหน้าอย่างเดียว กรณีของการแสดงผล
        .LockType = adLockReadOnly
        
        ' ปรับข้อมูลใหม่ใน Adodc1
        .Refresh
        
        ' นำเอาข้อมูลจากการ Query เพื่อทำการแสดงผลข้อมูล
        txtCustomerCode.Text = Adodc1.Recordset("CustomerCode")
        txtCustomerName.Text = Adodc1.Recordset("CustomerName")
        txtAddress.Text = Adodc1.Recordset("Address")
        txtAmphur.Text = Adodc1.Recordset("Amphur")
        txtPostCode.Text = Adodc1.Recordset("PostCode")
        
    End With
    
    ' นำค่า ProvinceName จาก Adodc1 ไปให้กับ DataCombo
    ' รับรองว่าไม่มีพลาดครับ ... หากเราเชื่อมความสัมพันธ์ และ กำหนดข้อมูลระหว่าง 2 ตารางได้ถูกต้อง
    DataCombo1.Text = Adodc1.Recordset("ProvinceName")
    
    Adodc1.Recordset.Close
    ' ไม่สามารถปิด Adodc2.Recordset.Close ... เพราะต้องผูกเข้ากับ DataCombo อยู่
    
    ' #####################################################
    ' พอเริ่มจะเซียนขึ้นมา ก็ต้องพัฒนาการเขียนโค้ดแบบ Run Time ประหยัด ADO Data Control
    ' ส่วนนี้คือการนำ Adodc1 กลับมาใช้งานอีกรอบ แต่เปลี่ยน RecordeSource ใหม่
    ' เพื่อ Query หารายชื่อจังหวัด นำมาแสดงผลลงใน DataCombo เสียก่อน
    ' ซึ่งผมจะนำมาใช้งานในตอนหน้าน่ะครับ ... ตอนนี้ก็ลองคิดเล่นๆไปพลางๆก่อนก็แล้วกัน
    ' #####################################################
    'Statement = "SELECT tblCustomer.ProvinceFK, tblProvince.ProvinceName " & _
                    " FROM tblProvince INNER JOIN tblCustomer ON " & _
                    " tblProvince.ProvincePK = tblCustomer.ProvinceFK " & _
                    " WHERE ProvinceName = " & "'" & ProvinceName & "'"

    'If Adodc1.Recordset.State <> 0 Then Adodc1.Recordset.Close
    'Adodc1.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                " Data Source=" & App.Path & "\MyDB.mdb;" & _
                " Persist Security Info=False"
    'Adodc1.CursorLocation = adUseClient
    'Adodc1.CommandType = adCmdText
    'Adodc1.RecordSource = Statement
    'Adodc1.Refresh
    
    'Set DataCombo1.DataSource = Adodc1
    'DataCombo1.DataField = "ProvinceName"
    
    ' ก่อนถึงบรรทัดคำสั่งนี้ ต้องเก็บค่า ProvinceName จากการ Query การแสดงผลตัวแรกก่อน
    'DataCombo1.Text = ProvinceName
    ' #####################################################
    
End Sub

' #####################################################
' เกิดเหตุการณ์กดปุ่ม (Event) ... สั่งทำ Driven คือ
' - ตรวจสอบการป้อนข้อมูล
' - บันทึกผลเข้าสู่ตารางข้อมูล
' - กลับไปรายการหลัก
' #####################################################
Private Sub cmdSave_Click()

    ' การตรวจสอบค่าว่างในฟิลด์ที่สำคัญๆ และจำเป็น เช่น รหัสลูกค้า ชื่อลูกค้า
    ' ผมจะข้ามการทดสอบหารหัสลูกค้าที่ซ้ำกันออกไป ... สามารถดูรายละเอียดเพิ่มเติมได้จาก
    ' http://www.g2gnet.com/News ... หรือ เอาไปคิดเป็นการบ้านเองด้วยครับ
    If Trim(txtCustomerCode.Text) = "" Then
        MsgBox "กรุณาป้อนรหัสลูกค้าให้เรียบร้อยก่อนด้วย.", vbOKOnly + vbExclamation, "รายงานสถานะ"
        txtCustomerCode.SetFocus
        Exit Sub
    ElseIf Trim(txtCustomerName.Text) = "" Then
        MsgBox "กรุณาป้อนชื่อลูกค้าให้เรียบร้อยก่อนด้วย.", vbOKOnly + vbExclamation, "รายงานสถานะ"
        txtCustomerName.SetFocus
        Exit Sub
    
    End If
    
    ' #####################################################
    ' สั่งบันทึกข้อมูล ... ส่วนนี้ควรแยกออกเป็นโปรแกรมย่อย จะดีกว่า
    Statement = "SELECT tblCustomer.CustomerPK, tblCustomer.CustomerCode, " & _
                    " tblCustomer.CustomerName, tblCustomer.Address, tblCustomer.Amphur, " & _
                    " tblCustomer.ProvinceFK, tblProvince.ProvinceName, tblCustomer.PostCode " & _
                    " FROM tblCustomer INNER JOIN tblProvince ON " & _
                    " tblCustomer.ProvinceFK = tblProvince.ProvincePK " & _
                    " WHERE " & _
                    " [CustomerPK] = " & CustomerPrimaryKey & _
                    " ORDER BY CustomerPK "
    With Adodc1
        .RecordSource = Statement
        ' ต้องใช้ adCmdText แทน เพราะเราใช้ SQL Statement ไม่ได้ใช้ตาราง (adCmdTable)
        ' หากกำหนดเป็น adCmdTable จะเกิด Syntax error in FROM clause
        .CommandType = adCmdText
        .CursorLocation = adUseClient
        ' เมื่อต้องการบันทึกผล หรือ เขียนข้อมูลลงไปในตารางข้อมูล ต้องปรับใหม่
        .CursorType = adOpenKeyset
        .LockType = adLockOptimistic
        .Refresh
        
        .Recordset.Fields("CustomerCode") = "" & txtCustomerCode.Text
        .Recordset.Fields("CustomerName") = "" & txtCustomerName.Text
        .Recordset.Fields("Address") = "" & txtAddress.Text
        .Recordset.Fields("Amphur") = "" & txtAmphur.Text
    
        ' ต้องไปทำงานโปรแกรมย่อย CompareProvinceName เพื่อตรวจสอบค่าใน DataCombo
        ' ว่าตรงกับ Primary Key อะไร ... เพราะในตารางลูกค้า เราจะเก็บเฉพาะค่า ProvinceFK
        .Recordset.Fields("ProvinceFK") = CompareProvinceName
    
        .Recordset.Fields("PostCode") = "" & txtPostCode.Text
    
        ' บันทึกข้อมูลใหม่ (Update)
        .Recordset.Update
        
        ' ปิดการเชื่อมต่อกับตารางข้อมูล
        .Recordset.Close
    
    End With
    
    MsgBox "บันทึกข้อมูลเรียบร้อย.", vbOKOnly + vbInformation, "รายงานสถานะ"
    
    ' ปิดฟอร์มกลับไปที่โปรแกรมรายการหลัก
    Unload Me
    
End Sub

' #####################################################
' เนื่องจากต้องมีการส่งค่า Primary Key ของจังหวัดนั้นๆ กลับคืนไปเราจึงต้องใช้ฟังค์ชั่นแทน
' แต่ไม่มีการรับค่าเข้ามา นำค่า Text ที่อยู่ใน DataCombo มาทดสอบหาค่า Primary Key
' #####################################################
Function CompareProvinceName() As Integer
    
    Statement = "SELECT tblProvince.ProvincePK, tblProvince.ProvinceName " & _
                    " FROM tblProvince " & _
                    " WHERE ProvinceName = " & "'" & DataCombo1.Text & "'"
                            
    With Adodc2
        .RecordSource = Statement
        .CommandType = adCmdText
        .CursorLocation = adUseClient
        .LockType = adLockReadOnly
        .Refresh
    End With
    
    ' ส่งค่าคืนกลับ (แบบเลขจำนวนเต็ม) โดยใช้ชื่อฟังค์ชั่นของตัวมันเอง
    CompareProvinceName = Adodc2.Recordset("ProvincePK")
    
    ' ปิดการเชื่อมต่อกับตารางข้อมูล
    Adodc2.Recordset.Close
    
End Function

' #####################################################
' ก่อนปิดหน้าจอ ต้องตัดการการเชื่อมต่อไฟล์ฐานข้อมูลด้วย
' #####################################################
Private Sub Form_Unload(Cancel As Integer)
    
    If Adodc1.Recordset.ActiveConnection.State = adStateOpen Then
        Adodc1.Recordset.ActiveConnection.Close
        Set Adodc1.Recordset.ActiveConnection = Nothing
    End If
    If Adodc2.Recordset.ActiveConnection.State = adStateOpen Then
        Adodc2.Recordset.ActiveConnection.Close
        Set Adodc2.Recordset.ActiveConnection = Nothing
    End If

End Sub

Private Sub cmdExit_Click()
    Unload Me
End Sub

Conclusion:
เนื่องจากเกิดการผูกข้อมูล (Bound Data) เข้ากับ Control จึงทำให้ไม่จำเป็นต้องใช้งานคำสั่งพวก Loop For หรือ การทำซ้ำ (Repeat) เช่น Do While หรือ Do Until เลย ... สำหรับมือใหม่ๆก็เลยง่ายหน่อยล่ะครับ ... ผมฝากข้อคิดเอาไว้ด้วย เช่น หากทำการผูกข้อมูล Adodc1 เข้ากับ TextBox ต่างๆในฟอร์ม จะเกิดปัญหาอะไรขึ้น หรือ หากเราจะทำการเพิ่มข้อมูลเข้าไปล่ะ จะทำได้อย่างไร ... หรือ หากจะใช้ ADO Data Control แล้วเขียนโค้ดแบบ Run Time จะแก้ไขปรับปรุงได้ยังไงบ้าง ... เพราะหากเอาแต่โค้ดของผมไปลูบๆคลำๆแต่เพียงอย่างเดียวไป ก็ยังจะคงไม่เวิร์คหรอกครับ ... ขอให้ลองฝึกๆดูกันน่ะครับ ...

จี ทู จี เน็ต ดอต คอม - g2gNet Dot Com
เลขทะเบียนพาณิชย์อิเล็กทรอนิกส์ 0407314800231
CopyLeft © 2004 - 2099 g2gNet.Com All rights reserved.
Email: [email protected] หรือ โทร. 08-6862-6560