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++;
      
        }
    }


 

我从早就发现我自己真的不会写博客,大家看代码吧,比较清楚,嗨,小学语文没学好

posted @   架构师修行之路  阅读(2370)  评论(9编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示