开发框架搭建之初,需要有个良好的ORM。如:Entity Framework,iBatis.NET(myBatis)、PetaPoco。因为个人爱好原因,选择了轻量级的 Dapper 框架。
Dapper google code: http://code.google.com/p/dapper-dot-net/
Dapper github code: https://github.com/SamSaffron/dapper-dot-net
现在对 Dapper 要做的扩展是,支持 Entity 的 CRUD ,如:
Role entity; =
new
Role();
entity.RoleId = Guid.New();
... ...
int result = entity.Insert();
result = entity.Update();
result = entity.Delete();
entity = entity.GetEntity();
扩展预期做到以下几点:
(1) 当实体属性赋值有变化时,自动记录(比如:重新赋值主键RoleID)变更属性。
(2) 根据赋值变化记录,可以动态生成查询条件、更新字段语句。这个想法借鉴自EntityFramework。
(3) 能识别实体主键、自动生成列。在新增数据时,不插入到数据库。
接下来,开始设计与开发扩展。
设计图,什么的以后再补了,先贴代码了。
实体模型接口,空方法接口。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BpmExpress.Common.Models
{
public
interface IDbEntity
{
} }
实体模型抽象类型,基类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Text;
namespace BpmExpress.Common.Models
{
///
<summary>
///
数据实体基类.
///
</summary>
[Serializable]
public
abstract
partial
class DbEntity : IDbEntity, INotifyPropertyChanged
{
[NonSerialized]
private IList<
string> _changedProperties =
null;
public
event PropertyChangedEventHandler PropertyChanged;
public DbEntity()
{ }
///
<summary>
///
修改的属性列表.
///
</summary>
internal IList<
string> ChangedProperties
{
get
{
if (_changedProperties ==
null)
_changedProperties =
new List<
string>();
return _changedProperties;
}
}
protected
virtual
void OnPropertyChanged(
string propertyName)
{
if (!
this.ChangedProperties.Contains(propertyName))
{
this.ChangedProperties.Add(propertyName);
}
if (
this.PropertyChanged !=
null)
{
this.PropertyChanged.Invoke(
this,
new PropertyChangedEventArgs(propertyName));
}
}
}}
这个抽象类中,最主要的是 ChangedProperties,用存放实体模型变更属性。这样才能实现上面预期的 根据赋值变化记录,可以动态生成查询条件、更新字段语句。
对于 Dapper 扩展如下:
1. 增加
public
static
int
Insert(
this
DbEntity entity, DataBase db =
null
)
{
if (entity == null)
return 0;
db = GetDataBase(db);
EntityDefinition definition = EntityDefinition.GetEntityDefinition(entity.GetType()); // 获取实体定义
StringBuilder parameters = new StringBuilder();
StringBuilder values = new StringBuilder();
IList<string> changed = null;
if (entity != null && entity.ChangedProperties.Count > 0)
changed = entity.ChangedProperties; // 变更属性
foreach (var propertyName in changed)
{
if (definition.AutoGenerations.Contains(propertyName))
continue;
parameters.AppendFormat("{0},", propertyName);
values.AppendFormat("@{0},", propertyName);
}
if (parameters.Length > 1)
{
parameters.Length = parameters.Length - 1;
values.Length = values.Length - 1;
}
string sql = string.Format("insert into {0}({1}) values ({2})", definition.TableName, parameters, values);
int rowAffected = db.ExecuteNonQuery(sql, entity); // Dapper方法
return rowAffected;
}
2. 删除
public
static
int Delete(
this DbEntity entity, DataBase db =
null)
{
if (entity ==
null)
return
0;
db = GetDataBase(db);
EntityDefinition definition = EntityDefinition.GetEntityDefinition(entity.GetType());
IList<
string> changed =
null;
if (entity !=
null && entity.ChangedProperties.Count >
0)
changed = entity.ChangedProperties;
//
变更属性,生成删除条件
StringBuilder
where =
new StringBuilder();
if (changed.Count >
0)
{
foreach (
var propertyName
in changed)
{
where.AppendFormat(
"
{0}=@{0} and
", propertyName);
}
where.Length =
where.Length -
4;
}
else
{
where.Append(definition.GetPrimaryCommand());
//
获取主键,删除
}
string sql =
string.Format(
"
delete from {0} where {1}
", definition.TableName,
where);
Trace(sql);
int rowAffected = db.ExecuteNonQuery(sql, entity);
//
Dapper
return rowAffected;
}
3. 修改
public
static
int Update(
this DbEntity entity, DataBase db =
null)
{
if (entity ==
null)
return
0;
db = GetDataBase(db);
EntityDefinition definition = EntityDefinition.GetEntityDefinition(entity.GetType());
StringBuilder parameters =
new StringBuilder();
IList<
string> changed =
null;
if (entity !=
null && entity.ChangedProperties.Count >
0)
changed = entity.ChangedProperties;
//
变更的字段
if (changed ==
null || changed.Count ==
0)
throw
new Data.DbException(
"
不存在需要更新的属性
");
foreach (
var propertyName
in changed)
{
if (definition.AutoGenerations.Contains(propertyName))
continue;
parameters.AppendFormat(
"
{0}=@{0},
", propertyName);
}
parameters.Length = parameters.Length -
1;
//
根据主键更新
string sql =
string.Format(
"
update {0} set {1} where {2}
", definition.TableName, parameters, definition.GetPrimaryCommand());
Trace(sql);
int rowAffected = db.ExecuteNonQuery(sql, entity);
//
Dapper
return rowAffected; }
4. 查询
public
static IEnumerable<T> Select<T>(
this T entity,
string
orderby =
null, DataBase db =
null)
where T : DbEntity
{
if (entity ==
null)
return
null;
db = GetDataBase(db);
EntityDefinition definition = EntityDefinition.GetEntityDefinition(entity.GetType());
IList<
string> changed =
null;
if (entity !=
null && entity.ChangedProperties.Count >
0)
changed = entity.ChangedProperties;
//
拼接查询条件的属性
string sql =
string.Empty;
if (!
string.IsNullOrEmpty(
orderby))
orderby =
"
order by
" +
orderby;
if (changed !=
null && changed.Count >
0)
{
// 动态拼接查询条件
StringBuilder where = new StringBuilder();
foreach (var propertyName in changed)
{
where.AppendFormat(" {0}=@{0} and", propertyName);
}
where.Length = where.Length - 4;
sql = string.Format("select {0} from {1} where{2}{3}", definition.GetSelectCommand(), definition.TableName, where, orderby);
}
else
{ // 生成查询SQL
sql = string.Format("select {0} from {1}{2}", definition.GetSelectCommand(), definition.TableName, orderby);
}
Trace(sql);
IEnumerable<T> rows = db.ExecuteQuery<T>(sql, entity);
return rows;
}