昨天跟朋友聊天,发现他们的项目数据层使用的是最基础的纯SQL语句+SqlParameter进行数据交互的,大家知道SELECT、UPDATE、CREATE对于表的依赖性比较大,然后删除语句却不一样,它的语法比较简单,大致有以下几种:
1、DELETE FROM TableName
2、DELETE FROM TableName WHERE ID = idValue
3、DELETE FROM TableName WHERE ID IN (id1, id2, id3, id4....)
于是我们要实现这个简单的功能来简化比较常用的删除就比较容易了,主要保留2个数据,1个是TableName,另外1个就是ID了,如果实体类有基类的情况下,我们可以扩展基类,提供2个接口,让其他的实体类去实现来保存对应的TableName和ID。但是如果没有基类的话,我们也可以利用Attribute来实现这个功能。
Attribute代码如下:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class DbAttribute : Attribute
{
#region 变量
private string m_TableName = null;
private string m_PrimaryKey = null;
#endregion
#region 构造函数
public DbAttribute(string tableName, string primaryKey)
{
this.m_TableName = tableName;
this.m_PrimaryKey = primaryKey;
}
#endregion
#region 普通方法
public string GetDeleteAllSQL()
{
return string.Format(@"
DELETE
FROM
{0}", this.m_TableName);
}
/// <summary>
/// 获取根据主键删除表数据
/// </summary>
/// <typeparam name="TParam">数据库类型</typeparam>
/// <typeparam name="TPKValue">主键类型名</typeparam>
/// <param name="tPKValue">主键值</param>
/// <returns></returns>
public KeyValuePair<string, TParam[]> GetDeleteByPrimaryKeySQL<TParam, TPKValue>(TPKValue tPKValue)
where TParam : DbParameter, new()
{
var sql = string.Concat(this.GetDeleteAllSQL(), string.Format(@"
WHERE
{0} = :_pk_", this.m_PrimaryKey));
MarkParameter<TParam> markParameter = new MarkParameter<TParam>();
var arrDbParam = markParameter.CastMark(ref sql, new Hashtable
{
{"_pk_", tPKValue}
});
return new KeyValuePair<string, TParam[]>(sql, arrDbParam);
}
/// <summary>
/// 获取根据主键数组删除表数据
/// </summary>
/// <typeparam name="TParam"></typeparam>
/// <typeparam name="TPKValue"></typeparam>
/// <param name="arrTPKValue"></param>
/// <returns></returns>
public KeyValuePair<string, TParam[]> GetDeleteInPrimaryKeySQL<TParam, TPKValue>(params TPKValue[] arrTPKValue)
where TParam : DbParameter, new()
{
var sql = string.Concat(this.GetDeleteAllSQL(), string.Format(@"
WHERE
{0} IN (:_arr_pk_)", this.m_PrimaryKey));
MarkParameter<TParam> markParameter = new MarkParameter<TParam>();
var arrDbParam = markParameter.CastMark(ref sql, new Hashtable
{
{"_arr_pk_", arrTPKValue}
});
return new KeyValuePair<string, TParam[]>(sql, arrDbParam);
}
#endregion
}
以上用到泛型模式以及前几篇文章提到的替换参数的方法,文章在此。有了以上的Attribute,我们就可以用它来标记实体类了,代码如下:
[Db("Permission_Info", "p_id")]
public partial class Permission
{
//属性、方法等
}
为了演示,我写了一个用来调用的方法,来测试产生的语句和参数。测试类代码如下:
public class DbOperate
{
public static string GetDeleteSQL<TClass>() where TClass : new()
{
var attr = GetAttribute<TClass>();
var sql = string.Empty;
if (null != attr)
{
sql = attr.GetDeleteAllSQL();
}
return sql;
}
public static KeyValuePair<string, SqlParameter[]> GetDeleteByIdSQL<TClass, TPKValUe>(params TPKValUe[] arrTPKValue) where TClass : new()
{
var attr = GetAttribute<TClass>();
KeyValuePair<string, SqlParameter[]> pair = new KeyValuePair<string, SqlParameter[]>(null, null);
if (null != attr)
{
if (1 == arrTPKValue.Length)
{
pair = attr.GetDeleteByPrimaryKeySQL<SqlParameter, TPKValUe>(arrTPKValue[0]);
}
else
{
pair = attr.GetDeleteInPrimaryKeySQL<SqlParameter, TPKValUe>(arrTPKValue);
}
}
return pair;
}
static DbAttribute GetAttribute<T>() where T : new()
{
var arrAttribute = typeof(T).GetCustomAttributes(typeof(DbAttribute), false);
DbAttribute attr = null;
if (0 < arrAttribute.Length)
{
attr = arrAttribute[0] as DbAttribute;
}
return attr;
}
}
代码测试如下:
以上代码并不是最优的选择,我们仍然可以在Attribute调用的地方进行优化,大家可以参考老赵的《Attribute操作的性能优化方式》