OpenAccess快速入門08
OpenAccess 快速入門將協助我們熟悉 OpenAccess,第八篇來聊聊如何在資料庫中加入一筆記錄。
在 ORM 的架構中,我們新增一筆資料,其實是建立一個新的 Entity,設定好屬性,然後把它加入物件容器,而這些動作,都不會即時反應回底層資料庫,除非我們在程式中,調用 SaveChanges() 函式:
如上兩圖所見,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" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<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>
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
執行結果: