using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
namespace CR
{
#region 定义的特性
/// <summary>
/// 定义实体与数据库的映射关系 (tabName:表名 primaryKey:主键列名 autoPrimarykey:主键是否自动编号)
/// 设计者 yixueli 2011-10-8
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] // multiuse attribute
public class Tab : Attribute //从Attribute 继承,写一个自定义属性
{
/// <summary>
/// 定义实体与数据库的映射关系 (tabName:表名 primaryKey:主键列名 autoPrimarykey:主键是否自动编号)
/// </summary>
public Tab(string tabName, string primaryKey, bool autoPrimarykey)
{
this.TabName = tabName;
this.Primarykey = primaryKey;
this.AutoPrimarykey = autoPrimarykey;
}
/// <summary>
/// 表名
/// </summary>
public string TabName { get; set; }
/// <summary>
/// 主键名
/// </summary>
public string Primarykey { get; set; }
/// <summary>
/// 主键是否为自动编号,即不需要程序生成
/// </summary>
public bool AutoPrimarykey { get; set; }
}
/// <summary>
/// 指定该属性绑定的字段名
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class Bind : Attribute
{
/// <summary>
/// 指定该属性绑定的字段名
/// </summary>
/// <param name="name"></param>
public Bind(string name)
{
this.Name = name;
}
/// <summary>
/// 绑定名
/// </summary>
public string Name { get; set; }
}
#endregion
/// <summary>
/// 数据持久化相关操作,可用于简单的实体与数据库对象的转换,简单的增删改查操作
/// </summary>
public class ORM
{
#region 实体属性反射
/// <summary>
/// 获取实体tab特性
/// </summary>
private static Tab GetTabAttribute(object entity)
{
var tabs = entity.GetType().GetCustomAttributes(typeof(Tab), true);
return (Tab)tabs[0];
}
private static Tab GetTabAttribute<T>() where T : new()
{
var tabs = typeof(T).GetCustomAttributes(typeof(Tab), true);
return (Tab)tabs[0];
}
/// <summary>
/// 获取属性对应的数据库字段
/// </summary>
private static string GetBindName(PropertyInfo property)
{
//如果定义了bind属性,则采用bind的定义,否则是属性名
var bind = property.GetCustomAttributes(typeof(Bind), true);
if (bind.Length > 0)
return ((Bind)bind[0]).Name;
else
return property.Name;
}
/// <summary>
/// 获取实体有效的属性数组,特定类型,排除不需要绑定的属性
/// </summary>
/// <param name="classType"></param>
/// <returns></returns>
private static PropertyInfo[] GetProperties(Type classType)
{
//允许的数据类型
string[] typeList = new string[]{
typeof(int).Name,
typeof(string).Name,
typeof(DateTime).Name,
typeof(bool).Name,
typeof(Guid).Name,
typeof(byte).Name
};
return classType.GetProperties().Where(m => typeList.Contains(m.PropertyType.Name)).ToArray();
}
/// <summary>
/// 把实体属性生成键值对(只取有效的实体属性)
/// </summary>
private static Dictionary<string, object> GetPropertyKeyValue(object entity)
{
Dictionary<string, object> list = new Dictionary<string, object>();
var proList = GetProperties(entity.GetType());
foreach (PropertyInfo item in proList)
{
var name = GetBindName(item);
list.Add(name.ToLower(), item.GetValue(entity, null));
}
return list;
}
/// <summary>
/// 根据sql语句和实体属性键值对生成参数数组
/// </summary>
private static SqlParameter[] GetCommandParameters(string sql, Dictionary<string, object> parames)
{
List<SqlParameter> p = new List<SqlParameter>();
string[] strArr = sql.Split(new char[] { ',', '=', ')', '(', ' ', '%', '\r' });
//查找
foreach (string s in strArr)
{
if (s.StartsWith("@"))
{
//已经赋值的不重复
if (p.Exists(m => m.ParameterName == s.ToLower()))
continue;
string key = s.Replace("@", "").ToLower();
if (parames.ContainsKey(key))
p.Add(new SqlParameter(s, parames[key] ?? DBNull.Value));
//else
// throw new ArgumentException("实体属性中没有找到与数据库对应的字段", key);
}
}
if (p.Count == 0)
return null;
return p.ToArray();
}
/// <summary>
/// 根据带参数形式的sql语句和实体 生成参数数组
/// </summary>
public static SqlParameter[] GetSqlParameters(string sql, object entity)
{
return GetCommandParameters(sql, GetPropertyKeyValue(entity));
}
#endregion
#region 把数据库对象转换成实体
/// <summary>
/// 通过反射绑定一个实体,默认绑定规则: 属性名=字段名 | 特殊规则:自定义特性Bind("name")=字段名
/// </summary>
public static T BindEntity<T>(SqlDataReader dr) where T : new()
{
if (dr.Read())
{
T entity = new T();
foreach (PropertyInfo item in GetProperties(entity.GetType()))
{
Type type = item.PropertyType;
string name = GetBindName(item);
//如果DataRow列名包含此属性
if (dr[name] != null)
{
//赋值
object value = Convert.ChangeType(dr[name], type);
item.SetValue(entity, value, null);
}
}
return entity;
}
else
return default(T);
}
/// <summary>
/// 通过反射绑定一个实体,默认绑定规则: 属性名=字段名 | 特殊规则:自定义特性Bind("name")=字段名
/// </summary>
public static T BindEntity<T>(DataTable tb) where T : new()
{
if (tb.Rows.Count == 0) return default(T);
return BindEntity<T>(tb.Rows[0]);
}
/// <summary>
/// 通过反射绑定一个实体,默认绑定规则: 属性名=字段名 | 特殊规则:自定义特性Bind("name")=字段名
/// </summary>
public static T BindEntity<T>(DataRow row) where T : new()
{
if (row == null) return default(T);
T entity = new T();
foreach (PropertyInfo item in GetProperties(entity.GetType()))
{
Type type = item.PropertyType;
string name = GetBindName(item);
//如果DataRow列名包含此属性
if (row[name] != null)
{
//赋值
object value = Convert.ChangeType(row[name], type);
item.SetValue(entity, value, null);
}
}
return entity;
}
/// <summary>
/// 把一张表绑定成实体列表
/// </summary>
public static List<T> BindEntityList<T>(DataTable tb) where T : new()
{
if (tb.Rows.Count == 0)
return default(List<T>);
List<T> list = new List<T>();
foreach (DataRow dr in tb.Rows)
{
list.Add(BindEntity<T>(dr));
}
return list;
}
#endregion
#region CRUD操作
/// <summary>
/// 向数据库插入数据,实体必须声明 Tab特性
/// </summary>
public static int Insert(object entity)
{
var tab = GetTabAttribute(entity);
var proList = GetPropertyKeyValue(entity);
//删除自增主键列
if (tab.AutoPrimarykey)
proList.Remove(tab.Primarykey.ToLower());
string key = string.Join(",", proList.Select(m => "[" + m.Key + "]"));
string val = string.Join(",", proList.Select(m => "@" + m.Key));
string sql = string.Format("insert into [{0}] ({1}) values ({2}) ", tab.TabName, key, val);
var p = GetCommandParameters(sql, proList);
return CR.SqlHelper.ExecuteNonQuery(CommandType.Text, sql, p);
}
/// <summary>
/// 修改实体,实体必须声明 Tab特性
/// </summary>
public static int Update(object entity)
{
var tab = GetTabAttribute(entity);
var proList = GetPropertyKeyValue(entity);
//生成set部分,不生成主键列
string set = string.Join(",", proList.Where(m => m.Key != tab.Primarykey.ToLower()).Select(m => string.Format("[{0}]=@{0}", m.Key)));
string sql = string.Format("update [{0}] set {1} where [{2}]=@{2}", tab.TabName, set, tab.Primarykey);
var p = GetCommandParameters(sql, proList);
return CR.SqlHelper.ExecuteNonQuery(CommandType.Text, sql, p);
}
/// <summary>
/// 通过主键删除一个实体对应的数据,实体必须声明 Tab特性
/// </summary>
public static int Delete<T>(object key) where T : new()
{
var tab = GetTabAttribute<T>();
var sql = string.Format("delete from [{0}] where [{1}]=@{1}", tab.TabName, tab.Primarykey);
var p = new SqlParameter("@" + tab.Primarykey, key);
return CR.SqlHelper.ExecuteNonQuery(CommandType.Text, sql, new SqlParameter[] { p });
}
/// <summary>
/// 通过主键获取一个实体 ,实体必须声明 Tab特性
/// </summary>
public static T Get<T>(object key) where T : new()
{
var tab = GetTabAttribute<T>();
string sql = string.Format("select top 1 * from [{0}] where [{1}]=@{1} ", tab.TabName, tab.Primarykey);
SqlParameter[] parames = new SqlParameter[1];
parames[0] = new SqlParameter("@" + tab.Primarykey, key);
return Get<T>(sql, parames);
}
/// <summary>
/// 通过自定义sql语句获取一个实体 ,实体必须声明 Tab特性
/// </summary>
public static T Get<T>(string sql) where T : new()
{
return Get<T>(CommandType.Text, sql, null);
}
/// <summary>
/// 通过自定义sql语句获取一个实体 ,实体必须声明 Tab特性
/// </summary>
public static T Get<T>(string sql, SqlParameter[] parames) where T : new()
{
return Get<T>(CommandType.Text, sql, parames);
}
/// <summary>
/// 通过自定义sql语句获取一个实体 ,实体必须声明 Tab特性
/// </summary>
public static T Get<T>(CommandType type, string sql, SqlParameter[] parames) where T : new()
{
using (DataTable tb = CR.SqlHelper.ExecuteDataTable(type, sql, parames))
{
return BindEntity<T>(tb);
}
}
/// <summary>
/// 获取所有数据,为了性能,最多1000条
/// </summary>
public static List<T> GetList<T>() where T : new()
{
var tab = GetTabAttribute(new T());
var sql = string.Format("select top 1000 * from [{0}]", tab.TabName);
return GetList<T>(CommandType.Text, sql, null);
}
/// <summary>
/// 根据sql语句获取实体列表
/// </summary>
public static List<T> GetList<T>(string sql) where T : new()
{
return GetList<T>(CommandType.Text, sql, null);
}
/// <summary>
/// 根据sql语句和参数获取实体列表
/// </summary>
public static List<T> GetList<T>(string sql, SqlParameter[] parames) where T : new()
{
return GetList<T>(CommandType.Text, sql, parames);
}
/// <summary>
/// 根据sql语句获取实体列表,可以通过CommandType来指定使用存储过程
/// </summary>
public static List<T> GetList<T>(CommandType type, string sql, SqlParameter[] parames) where T : new()
{
using (DataTable tb = SqlHelper.ExecuteDataTable(type, sql, parames))
{
return BindEntityList<T>(tb);
}
}
#endregion
}
}
ailin 写于2011年国庆
本类的功能分3个方面:
1.定义实体的特性(如对应的表名 主键名 属性对应的列名)
2.实体和数据库对象的相互转换
3.简单实体的 CRUD操作
全部代码 : (引用了一个SqlHelper数据库操作辅助类)