| 層級 | 技術實作 | 職責 |
|---|---|---|
| UI 層 (表現層) | ASP.NET Web Forms (.aspx + CodeBehind) | 使用者互動、資料呈現、輸入驗證、頁面流程控制 |
| BLL (商務邏輯層) | VB.NET/C# Class Library | 業務規則驗證、工作流程協調、資料轉換、呼叫 DAL |
| DAL (資料存取層) | ADO.NET (SqlClient/OleDb) + SQL Server | CRUD 操作、預存程序呼叫、連線管理、交易控制 |

SqlDataAdapter.Fill(DataSet):開啟連線 → 讀取資料 → 關閉連線 (連線池歸還)。DataSet (內含 DataTable、DataRelation、Constraint),**完全脫離資料庫**。DataAdapter.Update(DataSet) 重新開啟連線,以交易方式寫回變更。DataRelation)、約束 (PK/FK/Unique)。Public Class NewsDAL
Private ReadOnly _connStr As String = ConfigurationManager.ConnectionStrings("NewsDB").ConnectionString
Public Function GetNewsList() As DataTable
Using conn As New SqlConnection(_connStr)
Dim sql As String = "SELECT NewsID, Title, ClassID, PublishDate, IsTop FROM News ORDER BY IsTop DESC, PublishDate DESC"
Dim da As New SqlDataAdapter(sql, conn)
Dim dt As New DataTable()
da.Fill(dt)
Return dt
End Using
End Function
Public Function GetNewsById(newsID As Integer) As DataRow
Using conn As New SqlConnection(_connStr)
Dim sql As String = "SELECT * FROM News WHERE NewsID = @NewsID"
Dim cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("@NewsID", newsID)
Dim da As New SqlDataAdapter(cmd)
Dim dt As New DataTable()
da.Fill(dt)
Return If(dt.Rows.Count > 0, dt.Rows(0), Nothing)
End Using
End Function
Public Function InsertNews(title As String, classID As Integer, content As String, isTop As Boolean) As Integer
Using conn As New SqlConnection(_connStr)
Dim sql As String = "INSERT INTO News (Title, ClassID, Content, PublishDate, IsTop) VALUES (@Title, @ClassID, @Content, GETDATE(), @IsTop); SELECT SCOPE_IDENTITY();"
Dim cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("@Title", title)
cmd.Parameters.AddWithValue("@ClassID", classID)
cmd.Parameters.AddWithValue("@Content", content)
cmd.Parameters.AddWithValue("@IsTop", isTop)
conn.Open()
Return Convert.ToInt32(cmd.ExecuteScalar())
End Using
End Function
Public Function UpdateNews(newsID As Integer, title As String, classID As Integer, content As String, isTop As Boolean) As Boolean
Using conn As New SqlConnection(_connStr)
Dim sql As String = "UPDATE News SET Title=@Title, ClassID=@ClassID, Content=@Content, IsTop=@IsTop WHERE NewsID=@NewsID"
Dim cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("@NewsID", newsID)
cmd.Parameters.AddWithValue("@Title", title)
cmd.Parameters.AddWithValue("@ClassID", classID)
cmd.Parameters.AddWithValue("@Content", content)
cmd.Parameters.AddWithValue("@IsTop", isTop)
conn.Open()
Return cmd.ExecuteNonQuery() > 0
End Using
End Function
Public Function DeleteNews(newsID As Integer) As Boolean
Using conn As New SqlConnection(_connStr)
Dim sql As String = "DELETE FROM News WHERE NewsID = @NewsID"
Dim cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("@NewsID", newsID)
conn.Open()
Return cmd.ExecuteNonQuery() > 0
End Using
End Function
End Class
Public Class NewsBLL
Private ReadOnly _dal As New NewsDAL()
Public Function AddNews(title As String, classID As Integer, content As String, isTop As Boolean) As Integer
' 業務規則:標題不重複
If _dal.ExistsTitle(title) Then Throw New ArgumentException("標題已存在")
' 業務規則:分類必須存在
If Not New CategoryDAL().Exists(classID) Then Throw New ArgumentException("分類不存在")
Return _dal.InsertNews(title, classID, content, isTop)
End Function
Public Function GetPagedNews(pageIndex As Integer, pageSize As Integer, ByRef totalCount As Integer) As DataTable
Return _dal.GetPagedNews(pageIndex, pageSize, totalCount)
End Function
End Class
<asp:GridView ID="gvNews" runat="server" DataSourceID="odsNews"
AllowPaging="true" PageSize="15" AllowSorting="true"
DataKeyNames="NewsID" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="NewsID" HeaderText="ID" SortExpression="NewsID" />
<asp:BoundField DataField="Title" HeaderText="標題" SortExpression="Title" />
<asp:TemplateField HeaderText="分類">
<ItemTemplate>
<%# Eval("ClassName") %> <!-- 需 DAL JOIN 取得 -->
</ItemTemplate>
</TemplateField>
<asp:BoundField DataField="PublishDate" HeaderText="發布日期" DataFormatString="{0:yyyy/MM/dd}" SortExpression="PublishDate" />
<asp:CheckBoxField DataField="IsTop" HeaderText="置頂" SortExpression="IsTop" />
<asp:CommandField ShowEditButton="true" ShowDeleteButton="true" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="odsNews" runat="server"
TypeName="NewsBLL" SelectMethod="GetPagedNews"
DeleteMethod="DeleteNews" UpdateMethod="UpdateNews"
OnSelecting="odsNews_Selecting">
<SelectParameters>
<asp:Parameter Name="pageIndex" Type="Int32" />
<asp:Parameter Name="pageSize" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Protected Sub odsNews_Selecting(sender As Object, e As ObjectDataSourceSelectingEventArgs)
e.InputParameters("pageIndex") = gvNews.PageIndex
e.InputParameters("pageSize") = gvNews.PageSize
End Sub
ROW_NUMBER() OVER (ORDER BY ...) 或 OFFSET/FETCH (SQL 2012+) 只取當頁資料,避免全表撈入記憶體。Cache.Insert("Categories", GetAllCategories(), ..., 1小時),UI 繫結時查字典不查 DB。Pooling=true; Min Pool Size=5; Max Pool Size=100 (預設即開啟)。async/await + ExecuteReaderAsync 釋放執行緒提升併發。ASP.NET 三層架構配合 ADO.NET 斷開式資料模型,構建了高效能、可維護、可擴展的新聞管理系統基石。關鍵在於:DAL 專注資料存取細節 (參數化、連線池、分頁下推)、BLL 封裝業務不變量、UI 層善用資料繫結控制項與 ObjectDataSource 減少樣板代碼。理解斷開式架構「連線極短、資料在記憶體、批次更新」的精髓,才能發揮 ADO.NET 最大效能優勢。