三、实体层
实体对象通常是将底层的关系数据记录,表述为上层的数据对象,这一层次最主要的职责在于关系数据和实体之间的相互转换及实体的验证。从架构角度来讲我们可以通过下面的一些措施来帮助程序员开发:
1.开发实体对象基类,实现数据转换及验证框架,开发实体基类时我觉得至少要考虑以下几点:
a.提供缺省构造方法以及通过标记实体属性映射,来实现从IDataReader\DataRow\其他对象来填充数据实体的构造方法。
b.数据实体对象应为可序列化的,并且实现ICloneable接口。
c.为了通过关键字比较实体对象,还应重写Equals和GetHashCode方法,另外为了更友好显示实体信息可重写ToString()方法。
d.通过标记属性,在运行时通过反射实现实体单个属性的验证,而通过自定义的可重写的虚拟验证方法来实现复杂的,多属性的实体验证。
示例代码如下:
代码
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.Text;
using System.Xml.Serialization;
using Keyss.Framework.Entity.Validation;
using Keyss.Framework.Properties;
using Keyss.Framework.Utility;
namespace Keyss.Framework.Entity
{
/**//// <summary>
/// 所有数据实体对象基类,主要实现数据实体对象克隆及数据实体对象的xml文本表示
/// </summary>
[Serializable]
[MessageContract]
public abstract class EntityObject : ICloneable
{
private static readonly PropertyValidatorManager s_ValidatorManager = new PropertyValidatorManager();
construction#region construction
/**//// <summary>
/// 缺省构造函数
/// </summary>
public EntityObject()
{
}
/**//// <summary>
/// 由DataReader数据源填充数据实体
/// </summary>
/// <param name="dataReader">DataReader数据源</param>
public EntityObject(IDataReader dataReader)
{
EntityObjectBuilder.FillEntity(dataReader, this);
}
/**//// <summary>
/// 由DataRow数据源填充数据实体
/// </summary>
/// <param name="dataRow">DataRow数据源</param>
public EntityObject(DataRow dataRow)
{
EntityObjectBuilder.FillEntity(dataRow, this);
}
/**//// <summary>
/// 由其他实体数据源填充数据实体
/// </summary>
/// <param name="objDataSource">实体数据源</param>
public EntityObject(object objDataSource)
{
EntityObjectBuilder.FillEntity(objDataSource, this);
}
#endregion
IEntityDataSource function#region IEntityDataSource function
/**//// <summary>
/// 由DataReader数据源填充数据实体
/// </summary>
/// <param name="dataReader">DataReader数据源</param>
public void FillEntity(IDataReader dataReader)
{
EntityObjectBuilder.FillEntity(dataReader, this);
}
/**//// <summary>
/// 由DataRow数据源填充数据实体
/// </summary>
/// <param name="dataRow">DataRow数据源</param>
public void FillEntity(DataRow dataRow)
{
EntityObjectBuilder.FillEntity(dataRow, this);
}
/**//// <summary>
/// 由实体数据源填充数据实体
/// </summary>
/// <param name="objDataSource">实体数据源</param>
public void FillEntity(object objDataSource)
{
EntityObjectBuilder.FillEntity(objDataSource, this);
}
/**//// <summary>
/// 由数据实体更新DataRow数据源
/// </summary>
/// <param name="dataRow">DataRow数据源</param>
public void UpdateDataSource(DataRow dataRow)
{
EntityObjectBuilder.UpdateDataSource(dataRow, this);
}
/**//// <summary>
/// 由数据实体更新实体数据源
/// </summary>
/// <param name="objDataSource">实体数据源</param>
public void UpdateDataSource(object objDataSource)
{
EntityObjectBuilder.UpdateDataSource(objDataSource, this);
}
#endregion
ICloneable Members#region ICloneable Members
/**//// <summary>
/// 克隆当前数据实体对象
/// </summary>
/// <returns>返回克隆的对象</returns>
public virtual object Clone()
{
return SerializationHelper.Deserialize(SerializationHelper.Serialize(this));
}
#endregion
to string#region to string
/**//// <summary>
/// 数据实体对象的xml字串表示
/// </summary>
/// <returns>返回数据实体对象的xml字符串</returns>
public override string ToString()
{
using (var sw = new StringWriter())
{
var xs = new XmlSerializer(GetType());
xs.Serialize(sw, this);
return sw.ToString();
}
}
/**//// <summary>
/// 重载实体对象比较
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj.GetType() != GetType()) return false;
Dictionary<string, object> obj1Keys = GetPrimaryKeys();
Dictionary<string, object> obj2Keys = ((EntityObject) obj).GetPrimaryKeys();
foreach (string key in obj1Keys.Keys)
{
if (obj1Keys[key] == null || obj2Keys[key] == null || !obj1Keys[key].Equals(obj2Keys[key]))
{
return false;
}
}
return true;
}
/**//// <summary>
/// 重载实体对象Hash值
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
var sb = new StringBuilder();
Dictionary<string, object> objKeys = GetPrimaryKeys();
foreach (string key in objKeys.Keys)
{
object keyValue = objKeys[key];
if (keyValue != null)
{
sb.Append(keyValue);
}
}
return sb.ToString().GetHashCode();
}
#endregion
tools#region tools
/**//// <summary>
/// 利用反射返回当前对象的主键及其值的列表
/// </summary>
/// <returns>主键及其值的列表</returns>
public virtual Dictionary<string, object> GetPrimaryKeys()
{
var primaryKeys = new Dictionary<string, object>();
Type columnMappingAttributeType = typeof (ColumnMappingAttribute);
PropertyInfo[] propertyList =
GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in propertyList)
{
var attributes =
(ColumnMappingAttribute[]) propertyInfo.GetCustomAttributes(columnMappingAttributeType, false);
foreach (ColumnMappingAttribute attribute in attributes)
{
if (attribute.IsPrimaryKey)
{
primaryKeys.Add(propertyInfo.Name, propertyInfo.GetValue(this, null));
break;
}
}
}
return primaryKeys;
}
#endregion
validation#region validation
/**//// <summary>
/// 自定义验证器
/// </summary>
/// <param name="results">验证器结果集</param>
/// <param name="ruleset">规则集名称</param>
protected virtual void SelfValidate(ValidationResults results, string ruleset)
{
}
/**//// <summary>
/// 验证指定的验证集来验证数据实体对象
/// 对于实体对象的验证,验证以下三个层次
/// 第一获取实体对象真正的类型,利用指定的验证集验证实体
/// 第二获取实体对象真正的类型,利用缺省的验证集验证实体
/// 第二验证EntityObject对象,主要用来触发自定义验证
/// </summary>
/// <param name="ruleset">规则集名称</param>
/// <returns>验证结果</returns>
public virtual ValidationResults Validate(string ruleset)
{
ValidationResults results = s_ValidatorManager.Validate(this, ruleset);
SelfValidate(results, ruleset);
return results;
}
/**//// <summary>
/// 验证实体对象并抛出异常
/// </summary>
/// <param name="ruleset">规则集</param>
public void ValidateAndThrowException(string ruleset)
{
ValidationResults results = Validate(ruleset);
if (!results.IsValid)
{
throw new EntityValidationException(
string.Format(Resources.Culture, Resources.ExceptionEntityObjectIsInvalid, GetType().FullName),
results);
}
}
#endregion
}
}
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.Text;
using System.Xml.Serialization;
using Keyss.Framework.Entity.Validation;
using Keyss.Framework.Properties;
using Keyss.Framework.Utility;
namespace Keyss.Framework.Entity
{
/**//// <summary>
/// 所有数据实体对象基类,主要实现数据实体对象克隆及数据实体对象的xml文本表示
/// </summary>
[Serializable]
[MessageContract]
public abstract class EntityObject : ICloneable
{
private static readonly PropertyValidatorManager s_ValidatorManager = new PropertyValidatorManager();
construction#region construction
/**//// <summary>
/// 缺省构造函数
/// </summary>
public EntityObject()
{
}
/**//// <summary>
/// 由DataReader数据源填充数据实体
/// </summary>
/// <param name="dataReader">DataReader数据源</param>
public EntityObject(IDataReader dataReader)
{
EntityObjectBuilder.FillEntity(dataReader, this);
}
/**//// <summary>
/// 由DataRow数据源填充数据实体
/// </summary>
/// <param name="dataRow">DataRow数据源</param>
public EntityObject(DataRow dataRow)
{
EntityObjectBuilder.FillEntity(dataRow, this);
}
/**//// <summary>
/// 由其他实体数据源填充数据实体
/// </summary>
/// <param name="objDataSource">实体数据源</param>
public EntityObject(object objDataSource)
{
EntityObjectBuilder.FillEntity(objDataSource, this);
}
#endregion
IEntityDataSource function#region IEntityDataSource function
/**//// <summary>
/// 由DataReader数据源填充数据实体
/// </summary>
/// <param name="dataReader">DataReader数据源</param>
public void FillEntity(IDataReader dataReader)
{
EntityObjectBuilder.FillEntity(dataReader, this);
}
/**//// <summary>
/// 由DataRow数据源填充数据实体
/// </summary>
/// <param name="dataRow">DataRow数据源</param>
public void FillEntity(DataRow dataRow)
{
EntityObjectBuilder.FillEntity(dataRow, this);
}
/**//// <summary>
/// 由实体数据源填充数据实体
/// </summary>
/// <param name="objDataSource">实体数据源</param>
public void FillEntity(object objDataSource)
{
EntityObjectBuilder.FillEntity(objDataSource, this);
}
/**//// <summary>
/// 由数据实体更新DataRow数据源
/// </summary>
/// <param name="dataRow">DataRow数据源</param>
public void UpdateDataSource(DataRow dataRow)
{
EntityObjectBuilder.UpdateDataSource(dataRow, this);
}
/**//// <summary>
/// 由数据实体更新实体数据源
/// </summary>
/// <param name="objDataSource">实体数据源</param>
public void UpdateDataSource(object objDataSource)
{
EntityObjectBuilder.UpdateDataSource(objDataSource, this);
}
#endregion
ICloneable Members#region ICloneable Members
/**//// <summary>
/// 克隆当前数据实体对象
/// </summary>
/// <returns>返回克隆的对象</returns>
public virtual object Clone()
{
return SerializationHelper.Deserialize(SerializationHelper.Serialize(this));
}
#endregion
to string#region to string
/**//// <summary>
/// 数据实体对象的xml字串表示
/// </summary>
/// <returns>返回数据实体对象的xml字符串</returns>
public override string ToString()
{
using (var sw = new StringWriter())
{
var xs = new XmlSerializer(GetType());
xs.Serialize(sw, this);
return sw.ToString();
}
}
/**//// <summary>
/// 重载实体对象比较
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj.GetType() != GetType()) return false;
Dictionary<string, object> obj1Keys = GetPrimaryKeys();
Dictionary<string, object> obj2Keys = ((EntityObject) obj).GetPrimaryKeys();
foreach (string key in obj1Keys.Keys)
{
if (obj1Keys[key] == null || obj2Keys[key] == null || !obj1Keys[key].Equals(obj2Keys[key]))
{
return false;
}
}
return true;
}
/**//// <summary>
/// 重载实体对象Hash值
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
var sb = new StringBuilder();
Dictionary<string, object> objKeys = GetPrimaryKeys();
foreach (string key in objKeys.Keys)
{
object keyValue = objKeys[key];
if (keyValue != null)
{
sb.Append(keyValue);
}
}
return sb.ToString().GetHashCode();
}
#endregion
tools#region tools
/**//// <summary>
/// 利用反射返回当前对象的主键及其值的列表
/// </summary>
/// <returns>主键及其值的列表</returns>
public virtual Dictionary<string, object> GetPrimaryKeys()
{
var primaryKeys = new Dictionary<string, object>();
Type columnMappingAttributeType = typeof (ColumnMappingAttribute);
PropertyInfo[] propertyList =
GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in propertyList)
{
var attributes =
(ColumnMappingAttribute[]) propertyInfo.GetCustomAttributes(columnMappingAttributeType, false);
foreach (ColumnMappingAttribute attribute in attributes)
{
if (attribute.IsPrimaryKey)
{
primaryKeys.Add(propertyInfo.Name, propertyInfo.GetValue(this, null));
break;
}
}
}
return primaryKeys;
}
#endregion
validation#region validation
/**//// <summary>
/// 自定义验证器
/// </summary>
/// <param name="results">验证器结果集</param>
/// <param name="ruleset">规则集名称</param>
protected virtual void SelfValidate(ValidationResults results, string ruleset)
{
}
/**//// <summary>
/// 验证指定的验证集来验证数据实体对象
/// 对于实体对象的验证,验证以下三个层次
/// 第一获取实体对象真正的类型,利用指定的验证集验证实体
/// 第二获取实体对象真正的类型,利用缺省的验证集验证实体
/// 第二验证EntityObject对象,主要用来触发自定义验证
/// </summary>
/// <param name="ruleset">规则集名称</param>
/// <returns>验证结果</returns>
public virtual ValidationResults Validate(string ruleset)
{
ValidationResults results = s_ValidatorManager.Validate(this, ruleset);
SelfValidate(results, ruleset);
return results;
}
/**//// <summary>
/// 验证实体对象并抛出异常
/// </summary>
/// <param name="ruleset">规则集</param>
public void ValidateAndThrowException(string ruleset)
{
ValidationResults results = Validate(ruleset);
if (!results.IsValid)
{
throw new EntityValidationException(
string.Format(Resources.Culture, Resources.ExceptionEntityObjectIsInvalid, GetType().FullName),
results);
}
}
#endregion
}
}
2.编写生成工具,可以通过生成工具自动生成实体对象,生成文件时可以考虑以下措施
a.生成的实体类,最好分成两个文件,一个为{EntityName}Base.cs,而另一个为{EntityName}.cs,其中{EntityName}.cs中的类从{EntityName}Base.cs继承,而{EntityName}Base.cs再从架构中实体对象基类继承,所有生成的代码就保存在{EntityName}Base.cs中,我们可以在{EntityName}.cs中通过编写代码来重写底层中定义的属性及自验证方法等。
b.生成实体类时,最好直接从数据库中提取一些字段信息生成验证标记
示例代码如下:
代码
using System;
using System.Data;
using Keyss.Framework.Entity;
using Keyss.Framework.Entity.Validation.Validators;
using System.Runtime.Serialization;
namespace Keyss.Platform.Admin.Implementation.Entity
{
[Serializable]
public abstract class BusinessModuleEntityBase:EntityObject
{
construction#region construction
protected BusinessModuleEntityBase(){}
protected BusinessModuleEntityBase(IDataReader dataReader):base(dataReader){}
protected BusinessModuleEntityBase(DataRow dataRow):base(dataRow){}
protected BusinessModuleEntityBase(object obj):base(obj){}
#endregion
public properties#region public properties
/**//// <summary>
/// 业务模块编号
/// </summary>
[ColumnMapping( IsPrimaryKey=true)]
public virtual System.Int32 BusinessModuleID{get;set;}
/**//// <summary>
/// 名称
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 64, MessageTemplate="名称应为长度小于64的字符串")]
public virtual System.String Name{get;set;}
/**//// <summary>
/// 说明
/// </summary>
[ColumnMapping]
[StringLengthValidator(IgnoreNull = true,MaxLength = 256, MessageTemplate="说明应为空或长度小于256的字符串")]
public virtual System.String Description{get;set;}
/**//// <summary>
/// 链接字符串名称
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 64, MessageTemplate="链接字符串名称应为长度小于64的字符串")]
public virtual System.String ConnectionStringName{get;set;}
/**//// <summary>
/// 应用名称
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 64, MessageTemplate="应用名称应为长度小于64的字符串")]
public virtual System.String ApplicationName{get;set;}
/**//// <summary>
/// 命令超时时间
/// </summary>
[ColumnMapping]
public virtual System.Int32 CommandTimeout{get;set;}
/**//// <summary>
/// 接受注册
/// </summary>
[ColumnMapping]
public virtual System.Boolean AcceptRegistration{get;set;}
/**//// <summary>
/// 激活
/// </summary>
[ColumnMapping]
public virtual System.Boolean Actived{get;set;}
/**//// <summary>
/// 排序码
/// </summary>
[ColumnMapping]
public virtual System.Int32 OrderBy{get;set;}
/**//// <summary>
/// 修改人
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 32, MessageTemplate="修改人应为长度小于32的字符串")]
public virtual System.String Modifier{get;set;}
/**//// <summary>
/// 修改时间
/// </summary>
[ColumnMapping]
public virtual System.DateTime ModifiedDate{get;set;}
#endregion
}
}
using System.Data;
using Keyss.Framework.Entity;
using Keyss.Framework.Entity.Validation.Validators;
using System.Runtime.Serialization;
namespace Keyss.Platform.Admin.Implementation.Entity
{
[Serializable]
public abstract class BusinessModuleEntityBase:EntityObject
{
construction#region construction
protected BusinessModuleEntityBase(){}
protected BusinessModuleEntityBase(IDataReader dataReader):base(dataReader){}
protected BusinessModuleEntityBase(DataRow dataRow):base(dataRow){}
protected BusinessModuleEntityBase(object obj):base(obj){}
#endregion
public properties#region public properties
/**//// <summary>
/// 业务模块编号
/// </summary>
[ColumnMapping( IsPrimaryKey=true)]
public virtual System.Int32 BusinessModuleID{get;set;}
/**//// <summary>
/// 名称
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 64, MessageTemplate="名称应为长度小于64的字符串")]
public virtual System.String Name{get;set;}
/**//// <summary>
/// 说明
/// </summary>
[ColumnMapping]
[StringLengthValidator(IgnoreNull = true,MaxLength = 256, MessageTemplate="说明应为空或长度小于256的字符串")]
public virtual System.String Description{get;set;}
/**//// <summary>
/// 链接字符串名称
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 64, MessageTemplate="链接字符串名称应为长度小于64的字符串")]
public virtual System.String ConnectionStringName{get;set;}
/**//// <summary>
/// 应用名称
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 64, MessageTemplate="应用名称应为长度小于64的字符串")]
public virtual System.String ApplicationName{get;set;}
/**//// <summary>
/// 命令超时时间
/// </summary>
[ColumnMapping]
public virtual System.Int32 CommandTimeout{get;set;}
/**//// <summary>
/// 接受注册
/// </summary>
[ColumnMapping]
public virtual System.Boolean AcceptRegistration{get;set;}
/**//// <summary>
/// 激活
/// </summary>
[ColumnMapping]
public virtual System.Boolean Actived{get;set;}
/**//// <summary>
/// 排序码
/// </summary>
[ColumnMapping]
public virtual System.Int32 OrderBy{get;set;}
/**//// <summary>
/// 修改人
/// </summary>
[ColumnMapping]
[StringLengthValidator(MaxLength = 32, MessageTemplate="修改人应为长度小于32的字符串")]
public virtual System.String Modifier{get;set;}
/**//// <summary>
/// 修改时间
/// </summary>
[ColumnMapping]
public virtual System.DateTime ModifiedDate{get;set;}
#endregion
}
}