OpenAccess快速入門08

  • 1203
  • 0
  • 2013-10-13

OpenAccess快速入門08

DotBlogs Tags: , , , , ,

OpenAccess 快速入門將協助我們熟悉 OpenAccess,第八篇來聊聊如何在資料庫中加入一筆記錄。

----------

在 ORM 的架構中,我們新增一筆資料,其實是建立一個新的 Entity,設定好屬性,然後把它加入物件容器,而這些動作,都不會即時反應回底層資料庫,除非我們在程式中,調用 SaveChanges() 函式:

203308

203327

如上兩圖所見,OpenAccess 所提供的 SaveChanges 有兩個函式簽章,目前我們暫時只會用到第一個無參數的函式。

現在,我們在 Model 的專案中加入一個新的 CreateEntities.vb 類別,並加入適當的函式以建立和取回 Employees 的資料:


Public Class CreateEntities
    Private cxt As SecondModel
    Public Sub New()
        cxt = New SecondModel()
    End Sub

    Public Function CreateEmployee() As Long
        Dim newEmployee As New Employees()
        With newEmployee
            .FIRSTNAME = "Leo"
            .LASTNAME = "Shih"
            .TITLE = "CTO"
            .TITLEOFCOURTESY = "Mr."
            .BIRTHDATE = Date.Parse("2000/1/1")
            .HIREDATE = Date.Parse("2010/5/5")
            .COUNTRY = "台灣"
            .CITY = "新北市"
            .ADDRESS = "地球上的某處"
            .HOMEPHONE = "(02) 2882-5252"
            .EXTENSION = "123"
            .NOTES = "不要亂打電話喔!"
        End With
        cxt.Add(newEmployee)
        cxt.SaveChanges()
        Return newEmployee.EMPLOYEEID
    End Function

    Public Function GetEmployee(Id As Long) As Employees
        Dim emp = From x In cxt.Employees
                  Where x.EMPLOYEEID.Equals(Id)
                  Select x
        Return emp.FirstOrDefault()
    End Function

End Class

為求簡化和方便說明,所以直接在程式中寫死要建立的員工實體相關屬性。真實環境,當然會有一個介面讓使用者填寫資料。

請注意,Oracle 資料庫欄位並沒有像 MS SQL 自動增號(Auto Increment)的功能,所以理論上 EmployeeId 屬性應該要手動給值,但是上述程式我們並沒有賦予 EmployeeId 屬性值,原因為何?

這是因為我們所建立的 Employees 資料表,有一個觸發程序(Trigger),會幫我們做這件事:


CREATE OR REPLACE TRIGGER Employees_EmployeeID_TRIG BEFORE INSERT OR UPDATE ON Employees
FOR EACH ROW
DECLARE 
v_newVal NUMBER(12) := 0;
v_incval NUMBER(12) := 0;
BEGIN
  IF INSERTING AND :new.EmployeeID IS NULL THEN
    SELECT  Employees_EmployeeID_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
    -- If this is the first time this table have been inserted into (sequence == 1)
    IF v_newVal = 1 THEN 
      --get the max indentity value from the table
      SELECT NVL(max(EmployeeID),0) INTO v_newVal FROM Employees;
      v_newVal := v_newVal + 1;
      --set the sequence to that value
      LOOP
           EXIT WHEN v_incval>=v_newVal;
           SELECT Employees_EmployeeID_SEQ.nextval INTO v_incval FROM dual;
      END LOOP;
    END IF;
   -- assign the value from the sequence to emulate the identity column
   :new.EmployeeID := v_newVal;
  END IF;
END;

上述的 Trigger 會在新增資料到資料表之前,先去跟 Sequence 物件取一個新的流水號回來,然後把取回的流水號填到 Employees.EmployeeID 欄位。

※關於 Oracle 資料庫的特性,請自行參閱相關說明,在此僅針對比較容易有疑問的地方做簡單說明。

接下來,我們先寫個測試程式,確定 CreateEmployee 函式沒有問題,才不會花了大把時間在建立頁面,結果核心程式卻有問題。

這裡要來個題外話:雖然測試環境裡,我們的頁面也不過是幾個控制項,根本不花多少時間,但是實務中,頁面通常會有很多的事情要處理,而且做頁面的設計人員,可能並不是撰寫商業邏輯的開發人員,所以我還是傾向用真實環境的做法和各位說明。

另外,開發人員當然也可自行建立一個 Console專案/Web專案/MVC專案來測試寫好的函式,而且我個人以前也都這樣做,但是慢慢發現,在測試專案中寫測試,可以快速啟動測試、偵錯程式,開發流程較為順暢。

再多話一下,這裡的測試,純脆只是為了方便而已,千萬別以為單元測試就是這樣玩啊,差遠了!


<TestMethod()> _
Public Sub CreateEmployeeTest()
    Dim target As CreateEntities = New CreateEntities()
    Const expected As Long = 0
    Dim actual As Long = target.CreateEmployee()
    Assert.AreNotEqual(expected, actual)
    Assert.IsTrue(actual > expected)
End Sub

如何建立測試專案、測試類別和測試方法,在 OpenAccess快速入門02 說過了,這裡不再贅述。範例程式當然是一定會測試通過,所以其實這裡只是提供大家一個實務上會做的方式而已。

最後,我們還是要回到頁面上,把新增後的結果秀出來。請在 Web 專案中新增一個頁面 CreateNewEmployee.aspx,程式碼如下:


<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="CreateNewEmployee.aspx.vb" Inherits="OpenAccessWebApp01.CreateNewEmployee" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Button ID="btnCreate" runat="server" Text="建立新的Employee資料" />
            <hr />
            編號:<asp:Label ID="lblId" runat="server" Text=""></asp:Label><br />
            全名:<asp:Label ID="lblFullName" runat="server" Text=""></asp:Label><br />
            地址:<asp:Label ID="lblAddress" runat="server" Text=""></asp:Label><br />
            備註:<asp:Label ID="lblNote" runat="server" Text=""></asp:Label>
        </div>
    </form>
</body>
</html>

CreateNewEmployee.aspx.vb


Imports OpenAccessWebApp01Model

Public Class CreateNewEmployee
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    Private Sub btnCreate_Click(sender As Object, e As EventArgs) Handles btnCreate.Click
        Dim bo = New CreateEntities()
        Dim employeeId = bo.CreateEmployee()
        Dim employee = bo.GetEmployee(employeeId)
        lblId.Text = employee.EMPLOYEEID.ToString()
        lblFullName.Text = employee.FIRSTNAME + " " + employee.LASTNAME
        lblAddress.Text = employee.ADDRESS
        lblNote.Text = employee.NOTES
    End Sub
End Class

執行結果:

210129

--------
沒什麼特別的~
不過是一些筆記而已