二、打造实体基类

实体基类设计
本文介绍了一种基于泛型的实体基类设计方法,该方法能够适应不同类型的ID,并支持属性自动赋值、撤销操作及数据访问等功能。

二、打造实体基类

关系型数据表中一般有共性的部分是所有的实体都有ID(但ID的类型不一样),很多业务表都有主从的关系。

2.1表定义

比如下面的表

City定义

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,

[Version] [timestamp] 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,

[Version] [timestamp] NOT NULL,

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

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

CONSTRAINT [PK_BusinessOrderDetaileds] PRIMARY KEY CLUSTERED

BusinessOrderDetaileds的ID是uniqueidentifier类型,其外键对应的是BusinessOrders实体的ID。

2.2关于实体基类定义的要求

我希望有这个的实体基类,该实体定义了所有的继承者(实体的具体实现类)都必须有ID属性,但ID属性的数据类型由各实体自己定义。我还希望,能在类的定义上看出有主从表的关系,并且能约束主从表的一些行为。而且我还希望基类能自动的实现对属性的赋值。

2.3定义EntityBase

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类型。

2.4定义EntityBase的Undo功能

在没有泛型的年代时,基类无了解子类的类型,因此基类只能实现一些返回或参数是基本数据类型的方法,如果要为子类提供个性化的方法,基类只能以object对象返回,且要求子类实现数据类型的强制转换。但现在,EntityBase还提供了一个T类型,因此我们可以实现Undo的功能。

EntityBase(Undo部分)

/// <summary>

/// 实体是否支持撤销

/// </summary>

public abstract bool HasUndo

{

get;

}

/// <summary>

/// 还可以撤销的次数

/// </summary>

public int UndoCount

{

get

{

return undoStack.Count;

}

}

/// <summary>

/// 得到实体的副本

/// </summary>

/// <returns></returns>

protected virtual T Clone()

{

return (T)this.MemberwiseClone();

}

/// <summary>

/// 将复本入栈

/// </summary>

protected void Push()

{

if (this.HasUndo)

{

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

}

}

/// <summary>

/// 将复本入栈

/// </summary>

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

private void Push(T obj)

{

if (this.HasUndo)

{

undoStack.Push(obj.Clone());

}

}

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

/// <summary>

/// 将复本出栈

/// </summary>

/// <returns></returns>

private T Pop()

{

if (undoStack.Count > 0)

{

return undoStack.Pop();

}

else

{

return null;

}

}

/// <summary>

/// 撤销

/// </summary>

/// <returns></returns>

public T Undo()

{

return Pop();

}

使用了泛型,我们在类的内部提供了泛型队列,然后返回值和参数值都是泛型T,该T将由各个子类来具体实现。

2.5定义EntityBase的数据访问能力

/// <summary>

/// 根据给定的连接字符串构造数据提供者

/// </summary>

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

/// <returns></returns>

protected static DataProviders.IDataProvider CreateDataProvider(string connStr)

{

return new DataProviders.SqlDataProvider.SqlDataProvider(connStr);

}

2.6定义EntityBase的构造函数

EntityBase有一个接受System.Data.DataTable的构造函数,该构造函数将table中指定行的数据和本类的属性作对比,如果名称和数据类型匹配,则自动赋值。

EntityBase构造函数

/// <summary>

/// 按table的指定行数据进行属性的初始化

/// </summary>

/// <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);//赋值

}

else

{

if (pinfo.PropertyType.IsEnum)//如果对象属性的值是枚举类型

{

if (value.GetType() == typeof(int))//数据库中保存的是int类型,则直接为枚举赋值

{

pinfo.SetValue(this, value, null);//赋值

}

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);//赋值

}

}

}

}

}

2.7定义EntityBase的CreateInstance

虽然EntityBase的构造函数有能力实现对属性的自动赋值,但我们可能要实例对象的集合或决定table中是否有值,应此我们需要实现CreateInstance方法。

定义EntityBase的CreateInstances方法

/// <summary>

/// 通过table实例化一组对象

/// </summary>

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

/// <returns></returns>

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;

}

/// <summary>

/// 通过table实例化一个对象

/// </summary>

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

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

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

/// <returns></returns>

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

{

if (table.Rows.Count > rowIndex)

{

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

}

else

{

return null;

}

}

/// <summary>

/// 默认按table的第一行实例化一个对象

/// </summary>

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

/// <returns></returns>

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

{

return CreateInstance(table, 0);

}

/// <summary>

/// 通过table实例化一组对象

/// </summary>

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

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

/// <returns></returns>

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

{

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

}

/// <summary>

/// 通过table实例化一组对象

/// </summary>

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

/// <returns></returns>

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

{

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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值