﻿# 善用 LINQ to SQL 中的 partial class 機制進行資料格式驗證

我們通常會使用 DetailsView 或 FormView 控制項進行資料的新增、編輯、刪除等動作，而通常我們會在裡面放置許多 Validator 控制項以驗證資料格式是否正確，不過當進行較大的專案時，開發人數通常會比較多，而且人員之間的分工也會比較明確，有的人做 SA、有的人做 DBA、有的人做 ASP.NET UI Process 開發...等等，在分層負責的情況下若能夠有效分割工作，不但專案品質會比較高，大家在寫程式的過程中也會比較專注。

就拿驗證輸入資料的部分來討論，SA/SD 在傳遞專案規格給開發人員時，總是難免有東西沒講清楚，而導致某些資料輸入的驗證沒有做好；或者是專案需求不斷變更，而導致可能有些輸入驗證的規則遺漏了更新程式碼，若能從「資料的角度」出來來驗證輸入的資料，而非「操作介面的角度」來驗證資料，應該是比較直覺且有效的方式，而 LINQ to SQL 正好就實做出了這一點。

當我們用 LINQ to SQL Designer 設計完資料物件模型，預設就有定義一些你可以自行實做的 partial method，例如說[之前文章](/post/2008/04/27/SQL-2000-Uniquidentifier-problem-in-LINQ-to-SQL)提到過的 OnCreated() 方法，可用於資料物件(Entity)產生時給予資料物件的預設值。今天要講的是另一個 OnValidate() 方法，可用於當 LINQ to SQL 在執行 Insert, Update 或 Delete 等動作之前，對資料物件進行資料驗證的動作。

底下是一個簡單的驗證範例：

```
public partial class 產品資料
{
    partial void OnValidate(System.Data.Linq.ChangeAction action)
    {
        if (action == System.Data.Linq.ChangeAction.Insert 
            || action == System.Data.Linq.ChangeAction.Update)
        {
            if (!this._繳費方式.HasValue)
            {
                throw new Exception("您沒有輸入「繳費方式」無法儲存產品資料");
            }

            if (this.產品類別.名稱 == "電子商務類")
            {
                if (this.產品售價 < 2000)
                {
                    throw new Exception("電子商務類產品不得設定低於 2000 元。");
                }
            }
        }
    }
}
```

上面這段程式的「白話文」就是，當使用者要新增資料時或更新資料時，會先檢查「繳費方式」有沒有輸入資料，若沒輸入資料則丟出一個例外事件(Exception)。若「產品資料」的「產品類別」定義為「電子商務類」，當產品售價低於 2000 時則丟出一個例外事件(Exception)。

你可以看到我對產品類別的判斷條件跟「資料格式(Data Format)」是無關的，而是跟「商業邏輯(Business Logic)」有關係，在實務上資料格式異動的機會不太大（總是有例外的），但是商業邏輯就很有可能經常改變，將商業邏輯的判斷寫在這裡會比寫在每一支 ASP.NET 頁面程式裡來的清楚明瞭而直覺，不過這並不代表在 ASP.NET 頁面中就不需額外做出判斷，要做好一個完美的使用者介面，需要考量的細節是很多的，況且客戶的需求總是讓你料想不到，只是你可以把 OnValidate() 方法視為從 ASP.NET 輸入資料到 SQL Server 中的最後一道防線。

當然，你也可以把「最後一道防線」設定在資料庫系統中，例如說撰寫觸發程序(Trigger)或預儲程序(Stored Procedure)，但這沒有一定的規則，全看你怎麼規劃整個系統開發的架構，而我個人是偏好寫 C# 大於 T-SQL 啦。^\_^
