天天看點

二、打造實體基類二、打造實體基類

關系型資料表中一般有共性的部分是所有的實體都有ID(但ID的類型不一樣),很多業務表都有主從的關系。

比如下面的表

CREATE TABLE [lt_dictionary].[City](  

[CityID] [int] IDENTITY(1,1) NOT NULL,  

[Name] [nvarchar](50) NOT NULL,  

[PostalCode] [dbo].[PostalCodeType] NOT NULL,  

[DistanceCode] [nvarchar](5) NOT NULL,  

[Province] [nvarchar](3) NOT NULL,  

[Longitude] [decimal](5, 2) NOT NULL,  

[Latitude] [decimal](5, 2) NOT NULL,  

[Enable] [dbo].[EnableType] NOT NULL CONSTRAINT [DF_City_Enable] DEFAULT ((1)),  

[LastEditDate] [dbo].[BusinessDateType] NOT NULL CONSTRAINT [DF_City_LastEditDate] DEFAULT (getdate()),  

[UpdateDay] AS (datediff(day,[LastEditDate],getdate())),  

[Version] [timestamp] NOT NULL,  

CONSTRAINT [PK_City] PRIMARY KEY CLUSTERED   

(  

[CityID] ASC 

這個城市表的ID是int的。

BusinessOrders定義

CREATE TABLE [lt_business].[BusinessOrders](  

[BusinessOrderID] [uniqueidentifier] NOT NULL CONSTRAINT [DF_BusinessOrders_BusinessOrderID] DEFAULT (newid()),  

[Number] [dbo].[BusinessOrderType] NOT NULL CONSTRAINT [DF_BusinessOrders_Number] DEFAULT ([dbo].[CreateBusinessOrderNumber]('Bz')),  

[Deadline] [dbo].[BusinessDateType] NOT NULL,  

[PaymentMethod] [nchar](2) NOT NULL,  

[PaymentEnterprise] [dbo].[DescriptionType] NOT NULL,  

[Origin] [dbo].[DescriptionType] NOT NULL,  

[Destination] [dbo].[DescriptionType] NOT NULL,  

[DeliveryType] [nchar](2) NOT NULL,  

[Level] [dbo].[LevelType] NOT NULL,  

[Remark] [dbo].[DescriptionType] NOT NULL,  

[Indicator] [nvarchar](3) NOT NULL,  

[FreightPayable] [dbo].[DescriptionType] NOT NULL,  

[WarehouseID] [int] NOT NULL,  

[OrderID] [uniqueidentifier] NOT NULL,  

[BusinessDate] [dbo].[BusinessDateType] NOT NULL CONSTRAINT [DF_BusinessOrders_BusinessDate] DEFAULT (getdate()),  

[StaffID] [int] NOT NULL,  

[State] AS ([dbo].[GetBusinessOrderState]([BusinessOrderID])),  

CONSTRAINT [PK_BusinessOrders] PRIMARY KEY CLUSTERED  

BusinessOrders的ID是uniqueidentifier類型。

BusinessOrderDetaileds定義

CREATE TABLE [lt_business].[BusinessOrderDetaileds](  

[BusinessOrderDetailedID] [uniqueidentifier] NOT NULL CONSTRAINT [DF_BusinessOrderDetaileds_BusinessOrderDetailedID] DEFAULT (newid()),  

[BusinessOrderID] [uniqueidentifier] NOT NULL,  

[Serial] [int] NOT NULL,  

[GoodsDescription] [dbo].[DescriptionType] NOT NULL,  

[Packing] [nvarchar](2) NOT NULL,  

[Quantity] [decimal](18, 2) NOT NULL,  

[TotalPackages] [decimal](18, 2) NOT NULL,  

[Weight] [decimal](18, 2) NOT NULL,  

[Measurement] [decimal](18, 2) NOT NULL,  

[State] AS ([dbo].[GetBusinessOrderItmeState]([BusinessOrderDetailedID])),  

[CompleteQuantity] AS ([dbo].[GetBusinessOrderItmeCompleteQuantity]([BusinessOrderDetailedID])),  

CONSTRAINT [PK_BusinessOrderDetaileds] PRIMARY KEY CLUSTERED  

BusinessOrderDetaileds的ID是uniqueidentifier類型,其外鍵對應的是BusinessOrders實體的ID。

我希望有這個的實體基類,該實體定義了所有的繼承者(實體的具體實作類)都必須有ID屬性,但ID屬性的資料類型由各實體自己定義。我還希望,能在類的定義上看出有主從表的關系,并且能限制主從表的一些行為。而且我還希望基類能自動的實作對屬性的指派。

EntityBase定義(繼承部分)

[Serializable]  

public abstract class EntityBase<T,ID> where T : EntityBase<T,ID>  

{  

/// <summary>  

/// 所有的實體都必須有一個唯一辨別,具體類型有實體各自實作  

/// </summary>  

[System.ComponentModel.DataObjectField(true, true, false)]  

public virtual ID Identity  

set;  

get;  

}  

EntityBase定義了一個ID的泛型,該泛型描述了繼承者必須實作具體的ID類型。

在沒有泛型的年代時,基類無了解子類的類型,是以基類隻能實作一些傳回或參數是基本資料類型的方法,如果要為子類提供個性化的方法,基類隻能以object對象傳回,且要求子類實作資料類型的強制轉換。但現在,EntityBase還提供了一個T類型,是以我們可以實作Undo的功能。

EntityBase(Undo部分)

/// 實體是否支援撤銷  

public abstract bool HasUndo  

/// 還可以撤銷的次數  

public int UndoCount  

get  

return undoStack.Count;  

/// 得到實體的副本  

/// <returns></returns>  

protected virtual T Clone()  

return (T)this.MemberwiseClone();  

/// 将複本入棧  

protected void Push()  

if (this.HasUndo)  

this.Push((T)this.Clone());  

/// <param name="obj"></param>  

private void Push(T obj)  

undoStack.Push(obj.Clone());  

private System.Collections.Generic.Stack<T> undoStack = new Stack<T>();  

/// 将複本出棧  

private T Pop()  

if (undoStack.Count > 0)  

return undoStack.Pop();  

else 

return null;  

/// 撤銷  

public T Undo()  

return Pop();  

使用了泛型,我們在類的内部提供了泛型隊列,然後傳回值和參數值都是泛型T,該T将由各個子類來具體實作。

/// 根據給定的連接配接字元串構造資料提供者  

/// <param name="connStr"></param>  

protected static DataProviders.IDataProvider CreateDataProvider(string connStr)  

return new DataProviders.SqlDataProvider.SqlDataProvider(connStr);  

EntityBase有一個接受System.Data.DataTable的構造函數,該構造函數将table中指定行的資料和本類的屬性作對比,如果名稱和資料類型比對,則自動指派。

EntityBase構造函數

/// 按table的指定行資料進行屬性的初始化  

/// <param name="table"></param>  

/// <param name="indexRow"></param>  

public EntityBase(System.Data.DataTable table, int indexRow)  

//周遊table中的每一列  

for (int i = 0; i <= table.Columns.Count - 1; i++)  

//按列的名稱,試圖從目前對象中擷取同名屬性  

System.Reflection.PropertyInfo pinfo = this.GetType().GetProperty(table.Columns[i].ColumnName);  

if (pinfo != null)  

{//如果存在該屬性  

object value = table.Rows[indexRow][table.Columns[i].ColumnName];//提取列的目前行值  

if (pinfo.PropertyType == table.Columns[i].DataType)//如果對象屬性定義的類型和table的列的類型一緻  

pinfo.SetValue(this, value, null);//指派  

if (pinfo.PropertyType.IsEnum)//如果對象屬性的值是枚舉類型  

if (value.GetType() == typeof(int))//資料庫中儲存的是int類型,則直接為枚舉指派  

if (value.GetType() == typeof(string))//如果資料庫中儲存的是string類型  

pinfo.SetValue(this, Enum.Parse(pinfo.PropertyType, value.ToString(), false), null);//指派  

//如果對象的屬性是Bitmap類型,對應的資料值是byte[]  

if (pinfo.PropertyType==typeof(System.Drawing.Bitmap) && value.GetType()==typeof(byte[]))  

pinfo.SetValue(this, new System.Drawing.Bitmap(new System.IO.MemoryStream((byte[])value)), null);//指派  

雖然EntityBase的構造函數有能力實作對屬性的自動指派,但我們可能要執行個體對象的集合或決定table中是否有值,應此我們需要實作CreateInstance方法。

定義EntityBase的CreateInstances方法

/// 通過table執行個體化一組對象  

public static List<T> CreateInstances(System.Data.DataTable table, int startRecord, int maxRecords)  

List<T> instances = new List<T>();  

for (int i = startRecord; i <= maxRecords; i++)  

instances.Add(CreateInstance(table, i));  

return instances;  

/// 通過table執行個體化一個對象  

/// <param name="startRecord"></param>  

/// <param name="maxRecords"></param>  

public static T CreateInstance(System.Data.DataTable table, int rowIndex)  

if (table.Rows.Count > rowIndex)  

return (T)System.Activator.CreateInstance(typeof(T), table, rowIndex);  

/// 預設按table的第一行執行個體化一個對象  

public static T CreateInstance(System.Data.DataTable table)  

return CreateInstance(table, 0);  

public static List<T> CreateInstances(System.Data.DataTable table, int startRecord)  

return CreateInstances(table, startRecord, table.Rows.Count - 1);  

public static List<T> CreateInstances(System.Data.DataTable table)  

return CreateInstances(table, 0, table.Rows.Count - 1);  

本文轉自shyleoking 51CTO部落格,原文連結:

http://blog.51cto.com/shyleoking/805800