一个简易的ORM框架的实现(二)

  • 一个简易的ORM框架的实现(二)已关闭评论
  • 113 次浏览
  • A+
所属分类:.NET技术
摘要

把一个方向的技术研发做封装,具备通用性,让使用框架的开发者用起来很轻松。


框架目标

什么是框架,框架能做到什么?

把一个方向的技术研发做封装,具备通用性,让使用框架的开发者用起来很轻松。

属性:

  1. 通用性
  2. 健壮性
  3. 稳定性
  4. 扩展性
  5. 高性能
  6. 组件化
  7. 跨平台

从零开始-搭建框架

  1. 建立项目
  2. 主键查询功能开发
  3. 绑定实体

一步一步的给大家推导:
一边写一边测试

从零开始--搭建框架

1. 创建项目

首先,创建两个类库一个名为Models保存我们的模型,一个名为DbProxy的类库保存我们对数据库的核心操作。

先进行我们查询功能的编写,暂时不考虑通用性。

public class DbProxyCore {     public Commodity GetCommodity(int id)     {         string connectionString = "Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=*******";         Commodity commodity = new Commodity();         using (var connection = new SqlConnection(connectionString))         {             connection.Open();              string sql = @"SELECT [Id]                             ,[ProductId]                             ,[CategoryId]                             ,[Title]                             ,[Price]                             ,[Url]                             ,[ImageUrl]                             FROM [dbo].[Commodity] where Id="+id;              SqlCommand sqlCommand= connection.CreateCommand();             sqlCommand.CommandText = sql;             SqlDataReader reader= sqlCommand.ExecuteReader();//数据集的读取器                          if (reader.Read())             {                 commodity.Id = Convert.ToInt32(reader["Id"]);                 commodity.ProductId = Convert.ToInt64(reader["ProductId"]);                 commodity.CategoryId = Convert.ToInt32(reader["CategoryId"]);                 commodity.Title = reader["Title"].ToString();                    commodity.Price = Convert.ToDecimal(reader["Price"]);                 commodity.Url = reader["Url"].ToString();                 commodity.ImageUrl = reader["ImageUrl"].ToString();                                 }                      }         return commodity;     } } 

当我们又创建一个其他的model对象的时候,就遇到一个问题,难道我们需要每次都进行不同对象的独有的方法的创建吗?
并不是,这里就可以通过泛型来完成它们独有的方法
暂时的改造

  public T Find<T>(int id) where T : new()   {       string connectionString = """           Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=*********;           """;       T obj = new T();       using (var connection = new SqlConnection(connectionString))       {           connection.Open();            string sql = @"SELECT [Id]                           ,[ProductId]                           ,[CategoryId]                           ,[Title]                           ,[Price]                           ,[Url]                           ,[ImageUrl]                           FROM [dbo].[Commodity] where Id=" + id;            SqlCommand sqlCommand = connection.CreateCommand();           sqlCommand.CommandText = sql;           SqlDataReader reader = sqlCommand.ExecuteReader();//数据集的读取器            if (reader.Read())           {               //commodity.Id = Convert.ToInt32(reader["Id"]);               //commodity.ProductId = Convert.ToInt64(reader["ProductId"]);               //commodity.CategoryId = Convert.ToInt32(reader["CategoryId"]);               //commodity.Title = reader["Title"].ToString();               //commodity.Price = Convert.ToDecimal(reader["Price"]);               //commodity.Url = reader["Url"].ToString();               //commodity.ImageUrl = reader["ImageUrl"].ToString();           }        }       return obj;   }         

尝试运行,可以正确的运行,并不报错。

我们要给对象的属性赋值,不能通过new一个对象,直接调用对象的属性赋值;
这里就可以使用到我们的反射技术。

  public T Find<T>(int id) where T : new()   {       string connectionString = """           Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=7ujm&UJM;           """;       //T obj = new T();       Type type = typeof(T);       object? oResult = Activator.CreateInstance(type);        using (var connection = new SqlConnection(connectionString))       {           connection.Open();            string sql = @"SELECT [Id]                           ,[ProductId]                           ,[CategoryId]                           ,[Title]                           ,[Price]                           ,[Url]                           ,[ImageUrl]                           FROM [dbo].[Commodity] where Id=" + id;            SqlCommand sqlCommand = connection.CreateCommand();           sqlCommand.CommandText = sql;           SqlDataReader reader = sqlCommand.ExecuteReader();//数据集的读取器            if (reader.Read())           {               //commodity.Id = Convert.ToInt32(reader["Id"]);               //commodity.ProductId = Convert.ToInt64(reader["ProductId"]);               //commodity.CategoryId = Convert.ToInt32(reader["CategoryId"]);               //commodity.Title = reader["Title"].ToString();               //commodity.Price = Convert.ToDecimal(reader["Price"]);               //commodity.Url = reader["Url"].ToString();               //commodity.ImageUrl = reader["ImageUrl"].ToString();               foreach (var prop in type.GetProperties())               {                                         prop.SetValue(oResult, reader[prop.Name]);                                                                        }           }        }       return (T)oResult;   } 

还有就是sql语句的问题,如何通过T来生成不同的sql语句。
sql语句应该依赖于我们的泛型T,也通过T来动态生成不同的SQl的语句。

 public T Find<T>(int id) where T : new()  {      string connectionString = """          Data Source=10.10.32.242;Initial Catalog=AdvancedCustomerDB;Persist Security Info=True;User ID=sa;Password=********;          """;      //T obj = new T();      Type type = typeof(T);      object? oResult = Activator.CreateInstance(type);       using (var connection = new SqlConnection(connectionString))      {          connection.Open();           List<string> propNameList = type.GetProperties().Select(c => c.Name).ToList();          string strProps = string.Join(",", propNameList);           string sql = $"SELECT {strProps} FROM {type.Name} where Id=" + id;          //以逗号分割的数据库表的字段名称。                   SqlCommand sqlCommand = connection.CreateCommand();          sqlCommand.CommandText = sql;          SqlDataReader reader = sqlCommand.ExecuteReader();//数据集的读取器           if (reader.Read())          {              foreach (var prop in type.GetProperties())              {                                        prop.SetValue(oResult, reader[prop.Name]);                                                                      }          }       }      return (T)oResult;  } 

处理DBNULL的问题

prop.SetValue(oResult, reader[prop.Name] is DBNull ? null : reader[prop.Name]) ; 

这里还需要考虑如何避免传入如何的实体,导致报错的问题。
使用基类约束就能避免这个问题了。