OpenAccess快速入門10
OpenAccess 快速入門將協助我們熟悉 OpenAccess,第十篇來說明如何更新資料庫中的既有資料。
這篇文章我們說明如何更新資料庫中,既有的產品(Product)資料。首先,我們在 Model 專案中,加入新的類別 UpdateEntities.vb,並加入以下程式碼:
Public Class UpdateEntities
Private cxt As SecondModel
Public Sub New()
cxt = New SecondModel()
End Sub
Public Function UpdateProduct(Id As Long) As Products
Dim product = (From x In cxt.Products
Where x.PRODUCTID = Id
Select x).FirstOrDefault()
If product Is Nothing Then
Throw New System.NullReferenceException(String.Format("找不到編號:{0} 的產品資料。", Id))
End If
product.PRODUCTNAME = "進擊的巨人"
product.QUANTITYPERUNIT = "50 meters"
product.UNITPRICE = 888D
product.UNITSONORDER = 3L
product.UNITSINSTOCK = 9L
product.REORDERLEVEL = 11L
cxt.SaveChanges()
Return product
End Function
End Class
要更新既有資料,首先必須要找到想修改的資料,再調整資料實體物件的屬性,最後調用 SaveChanges() 函式回寫底層資料庫。上述 UpdateProduct 函式就是在做這些事情。
首先,我們透過 LINQ 取得指定編號的產品資料,這裡我們調用了 FirstOrDefault() 函式,然後如果傳入的產品編號找不到資料,我們就擲出 NullReferenceException,並設定錯誤訊息。若找的到資料,則我們就開始設定 product 實體物件的屬性值,最後調用物件容器(SecondModel)的 SaveChanges() 函式,將異動結果回寫資料庫。
同樣,我們撰寫單元測試案例來驗證上述程式碼的正確性:
<TestMethod()> _
<ExpectedException(GetType(System.NullReferenceException))> _
Public Sub UpdateProduct_RaiseException()
Dim target As UpdateEntities = New UpdateEntities()
Dim Id As Long = 99999999
Dim actual As Products = target.UpdateProduct(Id)
End Sub
<TestMethod()> _
Public Sub UpdateTempProduct()
Dim target As UpdateEntities = New UpdateEntities()
Dim Id = CreateTempProduct()
Dim actual As Products = target.UpdateProduct(Id)
Assert.IsNotNull(actual.UNITPRICE)
Assert.AreEqual(0L, actual.UNITSONORDER)
'TODO: 測試完成,刪除剛剛新增的測試資料。
End Sub
Private Function CreateTempProduct() As Long
Dim bo = New CreateEntities()
Dim product = bo.CreateProductAndCategory()
Return product.PRODUCTID
End Function
第一個測試 UpdateProduct_RaiseException() 故意傳入一個絕對不存在的產品編號給 UpdateEntities.UpdateProduct() 函式,預期會回傳一個 NullReferenceException。當然測試一定會通過,不然文章就寫不下去了咩。
第二個測試 UpdateTempProduct() 比較特別,使用和先前文章不同的測試方式,也是實務上會應用的一種做法:測試前先在資料庫中建立一筆測試用的資料,然後對此筆測試資料進行相關測試,最後測試完成後,再把此筆測試資料刪除。不過我們還沒說明如何透過 OpenAccess ORM 刪除資料,所以這裡只做了建立資料的動作。
當然,第二個測試也一定會通過,所以接下來我們回到 Web 專案,新增一個 DisplayAndUpdateProduct.aspx 頁面,放一個 GridView,並透過 LinkButton 更新選擇的產品資料:
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="DisplayAndUpdateProduct.aspx.vb" Inherits="OpenAccessWebApp01.DisplayAndUpdateProduct" %>
<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:GridView ID="gvProducts" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="動作">
<ItemTemplate>
<asp:LinkButton ID="btnUpdate" Text="更新資料" runat="server" CommandName="UpdateProduct" CommandArgument='<%#Eval("PRODUCTID")%>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="PRODUCTID">
<ItemTemplate>
<asp:Label ID="lblProductId" Text='<%# Eval("PRODUCTID")%>' runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="PRODUCTNAME">
<ItemTemplate>
<asp:Label ID="lblProductName" Text='<%# Eval("PRODUCTNAME")%>' runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="QUANTITYPERUNIT">
<ItemTemplate>
<asp:Label ID="lblQuantityPerUnit" Text='<%# Eval("QUANTITYPERUNIT")%>' runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="UNITSINSTOCK">
<ItemTemplate>
<asp:Label ID="lblUnitsInStock" Text='<%# Eval("UNITSINSTOCK")%>' runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="UNITSONORDER">
<ItemTemplate>
<asp:Label ID="lblUnitsOnOrder" Text='<%# Eval("UNITSONORDER")%>' runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="REORDERLEVEL">
<ItemTemplate>
<asp:Label ID="lblReOrderLevel" Text='<%# Eval("REORDERLEVEL")%>' runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
DisplayAndUpdateProduct.aspx.vb
Imports OpenAccessWebApp01Model
Public Class DisplayAndUpdateProduct
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
GridViewDataBinding()
End Sub
Private Sub gvProducts_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles gvProducts.RowCommand
Dim productId As Long = 0L
If Long.TryParse(e.CommandArgument, productId) Then
Dim updateBo = New UpdateEntities()
Dim product = updateBo.UpdateProduct(productId)
End If
GridViewDataBinding()
End Sub
Private Sub GridViewDataBinding()
Dim ProductBO = New ProductsMgmt()
gvProducts.DataSource = ProductBO.GetGiantProducts()
gvProducts.DataBind()
End Sub
End Class
為了讓上述程式碼可以執行,所以我們要再回到 Model 專案,新增一個 ProductMgmt 類別:
Public Class ProductsMgmt
Private cxt As SecondModel
Public Sub New()
cxt = New SecondModel()
End Sub
Public Function GetGiantProducts() As IList(Of Products)
Dim query = From x In cxt.Products
Where x.PRODUCTNAME.Contains("巨人")
Select x
Return query.ToList()
End Function
End Class
執行結果:
PS. 上面這張圖是 gif 動畫,但是在 Chrome 好像不會重覆播放,所以再留個連結,才不用重整畫面:http://i.minus.com/i4QFOpoucHBQ6.Gif