DAN疼之后上些基础知识---自己的ORM
在我”很小“的时候曾经有一个同事,工作经验比较丰富的那种,当时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++;
}
}
我从早就发现我自己真的不会写博客,大家看代码吧,比较清楚,嗨,小学语文没学好
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?