.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 = ;
  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 = ;
  58. foreach (MicroDataColumn column in Columns)
  59. {
  60. if (column.ColumnName == columnName)
  61. break;
  62. i++;
  63. }
  64. _ItemArray[i] = value;
  65. }
  66. }
  67. }

需要注意的是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, , 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, , 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 = ;
  8. int beginIndex = pageSize * pageIndex;
  9. int endIndex = pageSize * (pageIndex + ) - ;
  10.  
  11. while (reader.Read())
  12. {
  13. object[] values = new object[reader.FieldCount];
  14.  
  15. if (!defined)
  16. {
  17. for (int i = ; 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 = ; 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 = ;
  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 > && (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. }

面向云的.net core开发框架

4.5 .net core下直接执行SQL语句并生成DataTable的更多相关文章

  1. .net core下直接执行SQL语句并生成DataTable

    .net core可以执行SQL语句,但是只能生成强类型的返回结果.例如var blogs = context.Blogs.FromSql("SELECT * FROM dbo.Blogs& ...

  2. Entity Framework Core 执行SQL语句和存储过程

    无论ORM有多么强大,总会出现一些特殊的情况,它无法满足我们的要求.在这篇文章中,我们介绍几种执行SQL的方法. 表结构 在具体内容开始之前,我们先简单说明一下要使用的表结构. public clas ...

  3. EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery

    一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...

  4. Dos命令提示符下 - 用sqlcmd执行*.sql语句

    Dos命令提示符下 - 用sqlcmd执行*.sql语句 1)在Dos命令下执行sqlcmd命令(当然事先需要将sqlcmd增加到环境变量中去), 2)下面白色部分替换为服务器名或计算机名即可sqlc ...

  5. EF Core 执行SQL语句和存储过程

    无论ORM有多么强大,总会出现一些特殊的情况,它无法满足我们的要求.在这篇文章中,我们介绍几种执行SQL的方法. 表结构 在具体内容开始之前,我们先简单说明一下要使用的表结构. public clas ...

  6. 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据操作(二)

    CSSDesk body { background-color: #2574b0; } /*! zybuluo */ article,aside,details,figcaption,figure,f ...

  7. 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据操作

    http://www.cnblogs.com/wgp13x/p/4934521.html 内容一样,样式好的版本. 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据 ...

  8. EFCore执行Sql语句的方法:FromSql与ExecuteSqlCommand

    前言 在EFCore中执行Sql语句的方法为:FromSql与ExecuteSqlCommand:在EF6中的为SqlQuery与ExecuteSqlCommand,而FromSql和SqlQuery ...

  9. 使用Hive或Impala执行SQL语句,对存储在HBase中的数据操作

    CSSDesk body { background-color: #2574b0; } /*! zybuluo */ article,aside,details,figcaption,figure,f ...

随机推荐

  1. PostGIS(解压版)安装

    1.软件下载 postgresql-9.6.1-1-windows-x64-binaries.zip https://www.postgresql.org/download/windows/ post ...

  2. android Notification介绍

    如果要添加一个Notification,可以按照以下几个步骤 1:获取NotificationManager: NotificationManager m_NotificationManager=(N ...

  3. 简历生成平台项目开发-STEP1问卷设计

    周五课程结束完后,小组建立QQ群和微信群,着手讨论项目问题.一开始的大概想法:就业信息平台,收集企业招聘信息和就业生资料,提供给学生和企业的校企对接平台.后来发现群里谭卓同学也有个相关的思路,经过商量 ...

  4. (转)从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    原文地址:  http://www.cnblogs.com/lyhabc/p/4682028.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第二篇,主要讲述如何搭建故障转移集 ...

  5. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  6. nginx代理https站点(亲测)

    nginx代理https站点(亲测) 首先,我相信大家已经搞定了nginx正常代理http站点的方法,下面重点介绍代理https站点的配置方法,以及注意事项,因为目前大部分站点有转换https的需要所 ...

  7. emmet,jade,haml, slim,less,sass,coffeescript等的实战优缺点

    摘要: 文章背景,来自于群内周五晚上的一次头脑风暴式的思维碰撞交流活动. 随着前端技术的蓬勃发展, 各种新技术随着生产力的需要不断的涌入我们的视野, 那今天探讨的话题是这些新时代的前端兵器谱: 一. ...

  8. React-Native 动画优化

    前言 动画对于客户端来说是非常重要的一部分,直接影响到应用的用户体验.前端对于动画优化通常使用CSS3样式来实现动画,以利用GPU加速特性.而React-Native由于渲染模式的不同,无法使用CSS ...

  9. Spring Batch在大型企业中的最佳实践

    在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后进行一系列的后续处理.这样的过程就是" ...

  10. Java 序列化与反序列化

    1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频. ...