在我”很小“的时候曾经有一个同事,工作经验比较丰富的那种,当时asp.net还处在2.0 时代,做项目的时候当时还流行三层,我当时是个菜鸟(现在也是),看那个同事做三层的时候,早model层的属性和类上边加上一个特性,就可以实现这个类的增删改查,对于当时的我来说,已经很先进了。。。。
过了2年,虽然我依然很菜,但是在今天这个令人蛋疼的日子里,突然想起了这个功能,反正疼着也是疼着,不如来实现一下,顺便看看自己能不能做出来,经过了一天多的折腾,终于实现了其中简单的一点,不敢拿出来让大湿们look,只希望与刚工作的童鞋们一起分享一下,以共勉!!
环境:asp.net 4.0 + vs2010 +windows 2003 +SQL2005
一:特性部分:
[AttributeUsage(AttributeTargets.Class ,AllowMultiple =false , Inherited =true )]
public class TableAttribute:Attribute ,IError
{
public TableAttribute(string name)
{
if (!string.IsNullOrEmpty(name))
{
this.Name = name;
}
else
{
this.ErrorMessage = "TableAttribute必须对name进行初始化";
}
}
//表名
public string Name { get; set; }
//记录程序中的错误信息
public string ErrorMessage { get; set; }
}
因为我的这个orm,其实也不能算是orm,把表和列的特性分开了,所以会有两个类
[AttributeUsage(AttributeTargets.Property |AttributeTargets .Field , AllowMultiple = false, Inherited = true)]
public class ColumnAttribute:Attribute ,IError
{
public ColumnAttribute(string name, bool isAutomatic = false)
{
if (!string.IsNullOrEmpty(name))
{
this.Name = name;
}
else
{
this.ErrorMessage = "ColumnAttribute必须对name进行初始化";
}
this.IsAutomatic = isAutomatic;
}
//表名
public string Name { get; set; }
//记录程序中的错误信息
public string ErrorMessage { get; set; }
//是否为自动增长,默认为false
public bool IsAutomatic { get; set; }
}
对于其中的一些写法,无非是4.0里边的默认参数,还有以下的 扩展方法等等,木有什么高深的代码
二:model部分
[Table("student")]
public class Student:IModel
{
[Column("id", IsAutomatic = true)]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("age")]
public int Age { get; set; }
[Column("date")]
public DateTime date { get; set; }
}
三:数据库和类映射部分
我相信这部分就是像我这样的菜鸟最关心的部分了,为了作为数据的承载和缓存我新建了两个类,、
public class TableDTO
{
public string TablaName { get; set; }
public List<ColumnDTO> TableColumn { get; set; }
public IModel Class { get; set; }
}
public class ColumnDTO
{
public string ColumnName { get; set; }
public PropertyInfo Property { get; set; }
}
接下来就是正式的转化部分了,具体也不知道怎么讲,一看代码大家就明白了,
public static class ConvertToTable
{
/// <summary>
/// 将model类型转化为表-列的形式
/// </summary>
/// <returns></returns>
public static TableDTO GetTable<T>(this T t) where T :class ,IModel,new ()
{
var model = AttributeDic.Dics.FirstOrDefault(s=>s .Key ==typeof (T)) ;
if (model.Key !=null )
{
return model.Value;
}
var attribute = typeof(T).GetCustomAttributes(typeof(TableAttribute),true );
TableDTO table = new TableDTO();
table.TablaName = (attribute[0] as TableAttribute).Name;
table.Class =new T();
PropertyInfo[] infos = typeof(T).GetProperties();
List<ColumnDTO> columns = new List<ColumnDTO>();
foreach (PropertyInfo info in infos)
{
ColumnDTO column = new ColumnDTO();
if (info.GetCustomAttributes(typeof(ColumnAttribute), true).Length > 0)
{
column.ColumnName = (info.GetCustomAttributes(typeof(ColumnAttribute), true)[0] as ColumnAttribute).Name;
column.Property = info;
}
columns.Add(column);
}
table.TableColumn = columns;
if (!AttributeDic.Dics.ContainsKey (typeof(T)))
{
AttributeDic.Dics.Add(typeof(T), table);
}
return table;
}
}
这里关于IModel 这个借口没有什么好说的,纯粹就是一个约束而已,里边没有任何内容,关于PropertyInfo不熟悉的同学,自己可以查以下msdn,上边写的比我说的要清楚的多,至于AttributeDic.Dics 这个变量,纯粹是一个容器功能而已
public class AttributeDic { /// <summary> /// 作为缓存使用:<表明.列名,类名.属性名> /// </summary> public static Dictionary<Type, TableDTO> Dics = new Dictionary<Type, TableDTO>(); }
四:使用部分:
因为作为演示,所以我只做了一个插入数据的功能,扩展的同学自己可以发挥以下想想
public static class Operate { public static int Insert<T>(this T t, string where="") where T: class ,IModel,new () { TableDTO dto = ConvertToTable.GetTable(t); List<ColumnDTO> columns = dto.TableColumn.Where(s => s.Property.GetValue(t, null)!=null ).ToList(); StringBuilder strSql = new StringBuilder(); StringBuilder sbcolumn = new StringBuilder(); StringBuilder sbvalue = new StringBuilder(); int count=columns .Count; SqlParameter[] para=new SqlParameter [count]; int index=0; foreach (ColumnDTO columndto in columns) { if ((columndto .Property .GetCustomAttributes(typeof(ColumnAttribute), true)[0] as ColumnAttribute).IsAutomatic == true) { para = new SqlParameter[count-1]; continue; } sbcolumn.Append(columndto.ColumnName).Append(","); sbvalue.Append("@").Append(columndto.ColumnName).Append(",") ; para[index] = new SqlParameter("@"+columndto .ColumnName , columndto.Property.GetValue(t, null)); index++; } string strcolumn=sbcolumn.ToString(); string strvalue = sbvalue.ToString(); strSql.Append("insert into ").Append(dto.TablaName).Append(" (").Append(strcolumn.Substring(0, strcolumn.Length - 1)).Append(") values (").Append(strvalue .Substring (0,strvalue .Length -1)).Append(")"); SqlHelper.ExecuteNonQuery(SqlHelper .ConnectionString ,CommandType.Text ,strSql .ToString (),para ); return 1; } }
这部分无非就是拼接sql语句,构造参数而已,木有好讲的,仔细看一下就明白了,实现的比较粗糙,至于sqlhelper,我向大家都用过了,更不用多说了
现在来看客户端的调用:为了避免重复,我加了一个静态字段来标示不同
public partial class WebForm1 : System.Web.UI.Page
{
private static int index = 0;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Student stu = new Student() { Name ="姓名"+index , Age =index ,date =DateTime .Now };
stu.Insert();
index++;
}
}
我从早就发现我自己真的不会写博客,大家看代码吧,比较清楚,嗨,小学语文没学好