一個簡易的ORM框架的實現(二)

框架目標

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

把一個方向的技術研發做封裝,具備通用性,讓使用框架的開發者用起來很輕鬆。

屬性:

  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]) ;

這裏還需要考慮如何避免傳入如何的實體,導致報錯的問題。
使用基類約束就能避免這個問題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章