程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 4.5 .net core下直接執行SQL語句並生成DataTable,coredatatable

4.5 .net core下直接執行SQL語句並生成DataTable,coredatatable

編輯:關於.NET

4.5 .net core下直接執行SQL語句並生成DataTable,coredatatable


.net core可以執行SQL語句,但是只能生成強類型的返回結果。例如var blogs = context.Blogs.FromSql("SELECT * FROM dbo.Blogs").ToList()。而不允許返回DataSet、DataTable等弱類型。可能由於這個原因沒有實現在.net core中DataTable,然而DataTable還是可能會用到的。我們這裡就有一個數據倉庫的需求,允許用戶自行編寫類似SQL語句,然後執行,以表格展示。因為語句是千變萬化的,因此我也不知道用戶的語句輸出的是啥,更無法以類型來定義,因此只能采用DataTable方式。

之前.net framework下,可以通過dataadpater很方便的填充datatable,然後將datatable的數據推送到客戶端展示。但是.net core下,已經沒有DataTable和DataSet,我們只能自行實現MicroDataTable。

這裡我們也按照DataTable的方式,MicroDataTable的列定義為MicroDataColumn,行定義為MicroDataRow。代碼如下:

 

 1     public class MicroDataTable
 2     {
 3         /// <summary>
 4         /// 整個查詢語句結果的總條數,而非本DataTable的條數
 5         /// </summary>
 6         public int TotalCount { get; set; }
 7 
 8         public List<MicroDataColumn> Columns { get; set; } = new List<MicroDataColumn>();
 9 
10         public List<MicroDataRow> Rows { get; set; } = new List<MicroDataRow>();
11 
12         public MicroDataColumn[] PrimaryKey { get; set; }
13 
14         public MicroDataRow NewRow()
15         {
16             return new MicroDataRow(this.Columns, new object[Columns.Count]);
17         }
18     }
19 
20     public class MicroDataColumn
21     {
22         public string ColumnName { get; set; }
23         public Type ColumnType { get; set; }
24     }
25 
26     public class MicroDataRow
27     {
28         private object[] _ItemArray;
29         public List<MicroDataColumn> Columns { get; private set; }
30 
31         public MicroDataRow(List<MicroDataColumn> columns, object[] itemArray)
32         {
33             this.Columns = columns;
34             this._ItemArray = itemArray;
35         }
36 
37         public object this[int index]
38         {
39             get { return _ItemArray[index]; }
40             set { _ItemArray[index] = value; }
41         }
42         public object this[string columnName]
43         {
44             get
45             {
46                 int i = 0;
47                 foreach (MicroDataColumn column in Columns)
48                 {
49                     if (column.ColumnName == columnName)
50                         break;
51                     i++;
52                 }
53                 return _ItemArray[i];
54             }
55             set
56             {
57                 int i = 0;
58                 foreach (MicroDataColumn column in Columns)
59                 {
60                     if (column.ColumnName == columnName)
61                         break;
62                     i++;
63                 }
64                 _ItemArray[i] = value;
65             }
66         }
67 }
View Code

 

需要注意的是TotalCount屬性,在分頁情況下,是指查詢語句在數據庫中查詢出的所有記錄條數,而MicroDataTable的數據是當前頁面的記錄。

 

對於從數據庫中獲取DataTable的做法,采用類似SqlHelper的方式編寫DbContext的ExecuteDataTable擴展方法,傳入SQL語句和SQL語句的參數,生成MicroDataTable:

 

 1         public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, params object[] parameters)
 2         {
 3             var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>();
 4 
 5             using (concurrencyDetector.EnterCriticalSection())
 6             {
 7                 var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters);
 8 
 9                 RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues);
10 
11                 return MicroDataTableHelper.FillDataTable(query.DbDataReader, 0, int.MaxValue);
12             }
13         }
14 
15         public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, int pageIndex, int pageSize, params object[] parameters)
16         {
17             var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>();
18 
19             using (concurrencyDetector.EnterCriticalSection())
20             {
21                 var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters);
22 
23                 RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues);
24 
25                 return MicroDataTableHelper.FillDataTable(query.DbDataReader, 0, int.MaxValue);
26             }
27         }

 

這個方法還是需要部分.net framework core的技巧的,流程是根據SQL和參數創建原生的SQLCommand,執行ExecuteReader方法返回DataReader,再把DataReader填充到MicroDataTable中。注意的是,IConcurrencyDetector在.net core的描述是這樣的:This API supports the Entity Framework Core infrastructure and is not intended to be used directly from your code. This API may change or be removed in future releases。我們只能先這樣實現,以後看是否ef.core能否改變或者給出更好的方式。

上面程序中,最後有一句話MicroDataTableHelper.FillDataTable,這個方法的主要功能是從DataReader填充到MicroDataTable的。

 

 1         public static MicroDataTable FillDataTable(DbDataReader reader, int pageIndex, int pageSize)
 2         {
 3             bool defined = false;
 4 
 5             MicroDataTable table = new MicroDataTable();
 6 
 7             int index = 0;
 8             int beginIndex = pageSize * pageIndex;
 9             int endIndex = pageSize * (pageIndex + 1) - 1;
10 
11             while (reader.Read())
12             {
13                 object[] values = new object[reader.FieldCount];
14 
15                 if (!defined)
16                 {
17                     for (int i = 0; i < reader.FieldCount; i++)
18                     {
19                         MicroDataColumn column = new MicroDataColumn()
20                         {
21                             ColumnName = reader.GetName(i),
22                             ColumnType = reader.GetFieldType(i)
23                         };
24 
25                         table.Columns.Add(column);
26                     }
27 
28                     defined = true;
29                 }
30 
31                 if (index >= beginIndex && index <= endIndex)
32                 {
33                     reader.GetValues(values);
34 
35                     table.Rows.Add(new MicroDataRow(table.Columns, values));
36                 }
37 
38                 index++;
39             }
40 
41             table.TotalCount = index;
42 
43             return table;
44         }

 

上面這個程序,是按部就班的寫法,效率應該不太高。最近時間緊,沒有分析原先的Datatable裝載方式,以後有時間優化吧。下面給出一個當時用.net framework從datareader獲取分頁數據到datatable的程序,僅作參考。當時這段程序使用了table.beginloaddata/endloaddata方式,效率明顯有提升。

 1             using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
 2             {
 3                 int fieldCount = reader.FieldCount;
 4                 for (int i = 0; i < fieldCount; i++)
 5                 {
 6                     table.Columns.Add(reader.GetName(i), reader.GetFieldType(i));
 7                 }
 8 
 9                 object[] values = new object[fieldCount];
10                 int currentIndex = 0;
11                 int startIndex = pageSize * pageIndex;
12                 try
13                 {
14                     table.BeginLoadData();
15                     while (reader.Read())
16                     {
17                         if (startIndex > currentIndex++)
18                             continue;
19 
20                         if (pageSize > 0 && (currentIndex - startIndex) > pageSize)
21                             break;
22 
23                         reader.GetValues(values);
24                         table.LoadDataRow(values, true);
25                     }
26                 }
27                 finally
28                 {
29                     table.EndLoadData();
30                     try  //lgy:由於連接阿裡雲ADS數據庫cmd.Cancel()會報錯,所以把錯誤忽略了。
31                     {
32                         cmd.Cancel();
33                     }
34                     catch                 
35                     {                       
36                     }
37                     reader.Close();
38                 }
39             }

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved