最近公司项目开动了,出于各种考虑还是相对保守的采用 .NET 2.0 + 企业库 + SQLSERVER的大体框架.
为了封装单个实体对象的CRUD操作,遂自己动手写了一个orm实现的工具类库.
-------------------------------------------------------------------------------------------------------
首先,我们声明一个实体接口 IEntity
public
interface
IEntity : ICloneable
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
int ID
{ get; set; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
bool IsPersisted
{ get; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
IEntity
{ get; }
}
![](http://222.173.176.83:88/orm/ientity.jpg)
根据图示, IEntity接口实现ICloneable接口, 并且有三个属性
ID : 对应每个实体类型所对应的数据库表的主键ID (有一个前言约定: 所有表的主键id均为自增标识)
IsPersisted : 指示对象是否已持久化(对应到数据库表的一条记录)
Raw : 返回对象实例的已持久化的原始状态
有了实体,如何mapping到具体哪个数据表呢 ?
"约定优于配置", 因此我们直接使用Attribute来实现
public
class
EntityMappingAttribute : Attribute
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private string _tableName;
public string TableName
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _tableName; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _tableName = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public EntityMappingAttribute(string tableName)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
TableName = tableName;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
同理,为了建立实体Property到数据表字段的对应关系我们新建PropertyMappingAttribute类
public
class
PropertyMappingAttribute : Attribute
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private string _fieldName;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string FieldName
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _fieldName; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _fieldName = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public PropertyMappingAttribute()
{ }
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public PropertyMappingAttribute(string fieldName)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
FieldName = fieldName;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
经过上述处理, 一个十分简单的面向对象实体(Object)到关系型数据表(Relationship)的映射(Mapping)就已经声明完毕了.
既然前面声明了IEntity接口, 理所当然的我们应该实现它
public
abstract
class
EntityBase : IEntity
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private IEntity _raw;
private int _id;
private bool _isPersisted = false;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
IEntity Members#region IEntity Members
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// ID
/// </summary>
public virtual int ID
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _id; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _id = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual IEntity Raw
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _raw; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
protected set
{ _raw = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// 该对象是否已持久化
/// </summary>
public virtual bool IsPersisted
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _isPersisted; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
protected set
{ _isPersisted = value; }
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ICloneable Members#region ICloneable Members
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public object Clone()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Type type = this.GetType();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
object obj = Activator.CreateInstance(type);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (PropertyInfo p in type.GetProperties())
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
object value = p.GetValue(this,null);
p.SetValue(obj, value, null);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return obj;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
}
由于IEntity 实现了ICloneable接口, 实际上肩负重任的抽象类EntityBase需要实现两个接口.
因为我们不能向外界暴露设置实体是否持久化和原始状态的信息的设置器, 我们把set修饰为protected.
而实现ICloneable比较简单,就是利用反射构造出一个当前实体对象实例的拷贝.
基础工作差不多了, 让我们我们新建一个User
[Serializable]
[EntityMapping(
"
t_user
"
)]
public
class
User : EntityBase
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
[PropertyMapping]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string Name
{ get;set;}
public string Hello
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return "hello, I am "+Name;}
}
}
从前面的介绍可以知道,存在一个t_user表(字段有id,name),我们用User类来对应.
东西已经有了,如何使用是关键. 第一步我们要实现的是简单的Crud操作, 先声明一下管理这些操作的接口 IEntityManager
public
interface
IEntityManager
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
T Create<T>(T t) where T : IEntity;
void Update<T>(T t) where T : IEntity;
T Load<T>(int id) where T : IEntity;
void Delete<T>(int id) where T : IEntity;
List<T> LoadAll<T>() where T : IEntity;
}
在这里我们声明了几个泛型方法用来实现管理实体对象,并且约束其传入的参数必须实现我们上面声明IEntity接口
--------------------------------------------------
下一节,我们将完成IEntityManager是如何去实现管理实体的功能.