.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。代码如下:

     public class MicroDataTable
{
/// <summary>
/// 整个查询语句结果的总条数,而非本DataTable的条数
/// </summary>
public int TotalCount { get; set; } public List<MicroDataColumn> Columns { get; set; } = new List<MicroDataColumn>(); public List<MicroDataRow> Rows { get; set; } = new List<MicroDataRow>(); public MicroDataColumn[] PrimaryKey { get; set; } public MicroDataRow NewRow()
{
return new MicroDataRow(this.Columns, new object[Columns.Count]);
}
} public class MicroDataColumn
{
public string ColumnName { get; set; }
public Type ColumnType { get; set; }
} public class MicroDataRow
{
private object[] _ItemArray;
public List<MicroDataColumn> Columns { get; private set; } public MicroDataRow(List<MicroDataColumn> columns, object[] itemArray)
{
this.Columns = columns;
this._ItemArray = itemArray;
} public object this[int index]
{
get { return _ItemArray[index]; }
set { _ItemArray[index] = value; }
}
public object this[string columnName]
{
get
{
int i = ;
foreach (MicroDataColumn column in Columns)
{
if (column.ColumnName == columnName)
break;
i++;
}
return _ItemArray[i];
}
set
{
int i = ;
foreach (MicroDataColumn column in Columns)
{
if (column.ColumnName == columnName)
break;
i++;
}
_ItemArray[i] = value;
}
}
}

需要注意的是TotalCount属性,在分页情况下,是指查询语句在数据库中查询出的所有记录条数,而MicroDataTable的数据是当前页面的记录。

对于从数据库中获取DataTable的做法,采用类似SqlHelper的方式编写DbContext的ExecuteDataTable扩展方法,传入SQL语句和SQL语句的参数,生成MicroDataTable:

         public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, params object[] parameters)
{
var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>(); using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters); RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues); return MicroDataTableHelper.FillDataTable(query.DbDataReader, , int.MaxValue);
}
} public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, int pageIndex, int pageSize, params object[] parameters)
{
var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>(); using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters); RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues); return MicroDataTableHelper.FillDataTable(query.DbDataReader, , int.MaxValue);
}
}

这个方法还是需要部分.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的。

         public static MicroDataTable FillDataTable(DbDataReader reader, int pageIndex, int pageSize)
{
bool defined = false; MicroDataTable table = new MicroDataTable(); int index = ;
int beginIndex = pageSize * pageIndex;
int endIndex = pageSize * (pageIndex + ) - ; while (reader.Read())
{
object[] values = new object[reader.FieldCount]; if (!defined)
{
for (int i = ; i < reader.FieldCount; i++)
{
MicroDataColumn column = new MicroDataColumn()
{
ColumnName = reader.GetName(i),
ColumnType = reader.GetFieldType(i)
}; table.Columns.Add(column);
} defined = true;
} if (index >= beginIndex && index <= endIndex)
{
reader.GetValues(values); table.Rows.Add(new MicroDataRow(table.Columns, values));
} index++;
} table.TotalCount = index; return table;
}

上面这个程序,是按部就班的写法,效率应该不太高。最近时间紧,没有分析原先的Datatable装载方式,以后有时间优化吧。下面给出一个当时用.net framework从datareader获取分页数据到datatable的程序,仅作参考。当时这段程序使用了table.beginloaddata/endloaddata方式,效率明显有提升。

             using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
int fieldCount = reader.FieldCount;
for (int i = ; i < fieldCount; i++)
{
table.Columns.Add(reader.GetName(i), reader.GetFieldType(i));
} object[] values = new object[fieldCount];
int currentIndex = ;
int startIndex = pageSize * pageIndex;
try
{
table.BeginLoadData();
while (reader.Read())
{
if (startIndex > currentIndex++)
continue; if (pageSize > && (currentIndex - startIndex) > pageSize)
break; reader.GetValues(values);
table.LoadDataRow(values, true);
}
}
finally
{
table.EndLoadData();
try //lgy:由于连接阿里云ADS数据库cmd.Cancel()会报错,所以把错误忽略了。
{
cmd.Cancel();
}
catch
{
}
reader.Close();
}
}

面向云的.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. 学习C的笔记

    [unsigned] 16位系统中一个int能存储的数据的范围为-32768~32767,而unsigned能存储的数据范围则是0~65535.由于在计算机中,整数是以补码形式存放的.根据最高位的不同 ...

  2. Android开发案例 – 在AbsListView中使用倒计时

    在App中, 有多种多样的倒计时需求, 比如: 在单View上, 使用倒计时, 如(如图-1) 在ListView(或者GridView)的ItemView上, 使用倒计时(如图-2) 图-1 图-2 ...

  3. 设置WindowServer2012 时间同步NTP

    在powershell中以管理员身份运行以下命令即可 w32tm /config /manualpeerlist:pool.ntp.org /syncfromflags:MANUAL Stop-Ser ...

  4. 简述 OAuth 2.0 的运作流程

    本文将以用户使用 github 登录网站留言为例,简述 OAuth 2.0 的运作流程. 假如我有一个网站,你是我网站上的访客,看了文章想留言表示「朕已阅」,留言时发现有这个网站的帐号才能够留言,此时 ...

  5. 如何在 Visual Studio 中使用 Git 同步代码到 CodePlex

    开源社区不管在国内还是国外都很火热,微软也曾因为没有开源而倍受指责,但是随着 .Net framework.ASP.Net MVC等框架的逐渐开源,也让大家看到了微软开源的步伐.CodePlex 则是 ...

  6. .NET基础 一步步 一幕幕[循环、逻辑语句块]

    循环.逻辑语句块   好久不写博客了,断更了好几天了,从上周五到今天,从北京到上海,跨越了1213.0公里,从一个熟悉的城市到陌生的城市,还好本人适应力比较好,还有感谢小伙伴的接风咯,一切都不是事,好 ...

  7. 给WinForm窗体添加快捷键 响应回车键、空格键

    1.设置窗体KeyPreview属性为True 2.添加窗体的KeyDown事件 /// <summary> /// 窗体的keydown事件响应 添加快捷键 /// </summa ...

  8. Angular页面传参的四种方法

    1. 基于ui-router的页面跳转传参 (1)在Angular的app.js中用ui-route定义路由,比如有两个页面, 一个页面(producers.html)放置了多个producers,点 ...

  9. C#设计模式-访问者模式

    一. 访问者(Vistor)模式 访问者模式是封装一些施加于某种数据结构之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保存不变.访问者模式适用于数据结构相对稳定的系统, 它把数据结 ...

  10. 常用的Webpack配置

    官方文档: http://webpack.github.io/docs/ 1. 安装python2. 安装node.js msi3. npm自动打包在最新的node.js安装包里 被封的包用国内镜像下 ...