当前位置:Gxlcms > asp.net > .Net core下直接执行SQL语句并生成DataTable的实现方法

.Net core下直接执行SQL语句并生成DataTable的实现方法

时间:2021-07-01 10:21:17 帮助过:46人阅读

.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. { /// <summary>
  3. /// 整个查询语句结果的总条数,而非本DataTable的条数
  4. /// </summary>
  5. public int TotalCount { get; set; }
  6. public List<MicroDataColumn> Columns { get; set; } = new List<MicroDataColumn>();
  7. public List<MicroDataRow> Rows { get; set; } = new List<MicroDataRow>();
  8. public MicroDataColumn[] PrimaryKey { get; set; }
  9. public MicroDataRow NewRow()
  10. {
  11. return new MicroDataRow(this.Columns, new object[Columns.Count]);
  12. }
  13. }
  14. public class MicroDataColumn
  15. {
  16. public string ColumnName { get; set; }
  17. public Type ColumnType { get; set; }
  18. }
  19. public class MicroDataRow
  20. {
  21. private object[] _ItemArray;
  22. public List<MicroDataColumn> Columns { get; private set; }
  23. public MicroDataRow(List<MicroDataColumn> columns, object[] itemArray)
  24. {
  25. this.Columns = columns;
  26. this._ItemArray = itemArray;
  27. }
  28. public object this[int index]
  29. {
  30. get { return _ItemArray[index]; }
  31. set { _ItemArray[index] = value; }
  32. }
  33. public object this[string columnName]
  34. {
  35. get
  36. {
  37. int i = 0;
  38. foreach (MicroDataColumn column in Columns)
  39. {
  40. if (column.ColumnName == columnName)
  41. break;
  42. i++;
  43. }
  44. return _ItemArray[i];
  45. }
  46. set
  47. {
  48. int i = 0;
  49. foreach (MicroDataColumn column in Columns)
  50. {
  51. if (column.ColumnName == columnName)
  52. break;
  53. i++;
  54. }
  55. _ItemArray[i] = value;
  56. }
  57. }
  58. }

需要注意的是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. using (concurrencyDetector.EnterCriticalSection())
  5. {
  6. var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters);
  7. RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues);
  8. return MicroDataTableHelper.FillDataTable(query.DbDataReader, 0, int.MaxValue);
  9. }
  10. }
  11. public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, int pageIndex, int pageSize, params object[] parameters)
  12. {
  13. var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>();
  14. using (concurrencyDetector.EnterCriticalSection())
  15. {
  16. var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters);
  17. RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues);
  18. return MicroDataTableHelper.FillDataTable(query.DbDataReader, 0, int.MaxValue);
  19. }
  20. }

这个方法还是需要部分.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. MicroDataTable table = new MicroDataTable();
  5. int index = 0;
  6. int beginIndex = pageSize * pageIndex;
  7. int endIndex = pageSize * (pageIndex + 1) - 1;
  8. while (reader.Read())
  9. {
  10. object[] values = new object[reader.FieldCount];
  11. if (!defined)
  12. {
  13. for (int i = 0; i < reader.FieldCount; i++)
  14. {
  15. MicroDataColumn column = new MicroDataColumn()
  16. {
  17. ColumnName = reader.GetName(i),
  18. ColumnType = reader.GetFieldType(i)
  19. };
  20. table.Columns.Add(column);
  21. }
  22. defined = true;
  23. }
  24. if (index >= beginIndex && index <= endIndex)
  25. {
  26. reader.GetValues(values);
  27. table.Rows.Add(new MicroDataRow(table.Columns, values));
  28. }
  29. index++;
  30. }
  31. table.TotalCount = index;
  32. return table;
  33. }

上面这个程序,是按部就班的写法,效率应该不太高。最近时间紧,没有分析原先的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. object[] values = new object[fieldCount];
  9. int currentIndex = 0;
  10. int startIndex = pageSize * pageIndex;
  11. try
  12. {
  13. table.BeginLoadData();
  14. while (reader.Read())
  15. {
  16. if (startIndex > currentIndex++)
  17. continue;
  18. if (pageSize > 0 && (currentIndex - startIndex) > pageSize)
  19. break;
  20. reader.GetValues(values);
  21. table.LoadDataRow(values, true);
  22. }
  23. }
  24. finally
  25. {
  26. table.EndLoadData();
  27. try //lgy:由于连接阿里云ADS数据库cmd.Cancel()会报错,所以把错误忽略了。
  28. {
  29. cmd.Cancel();
  30. }
  31. catch
  32. {
  33. }
  34. reader.Close();
  35. }
  36. }

以上所述是小编给大家介绍的.Net core下直接执行SQL语句并生成DataTable,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

人气教程排行