.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 = 0; foreach (MicroDataColumn column in Columns) { if (column.ColumnName == columnName) break; i++; } return _ItemArray[i]; } set { int i = 0; 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, 0, 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, 0, 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 = 0; int beginIndex = pageSize * pageIndex; int endIndex = pageSize * (pageIndex + 1) - 1; while (reader.Read()) { object[] values = new object[reader.FieldCount]; if (!defined) { for (int i = 0; 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 = 0; i < fieldCount; i++) { table.Columns.Add(reader.GetName(i), reader.GetFieldType(i)); } object[] values = new object[fieldCount]; int currentIndex = 0; int startIndex = pageSize * pageIndex; try { table.BeginLoadData(); while (reader.Read()) { if (startIndex > currentIndex++) continue; if (pageSize > 0 && (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下直接执行SQL语句并生成DataTable,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
本文向大家介绍SQL Server 2005 定时执行SQL语句的方法,包括了SQL Server 2005 定时执行SQL语句的方法的使用技巧和注意事项,需要的朋友参考一下 SQL SERVER 2005有定时任务,你可以启动一下。不过要想更加直观的控制,直接写一个程序,定时执行你的存储过程。 1、设置“SQL Server 代理”(SQL Server Agent)服务随系统启动 --我的电脑
下面给出一个例子来演示一下如何使用JDBC来执行各种SQL语句,其中包括DDL语句(建立数据库和数据表)、INSERT语句和SELECT语句。 1.程序分析说明 本程序首先创建一个mydb数据库(如果存在就不创建),然后创建一个用于保存图书信息的表t_books(如果存在,删除后再创建),最后向表中插入两条记录,并查询和显示其中的第2条记录。 2.代码编写 本程序使用了Statement接口的ex
问题内容: 将NHibernate配置为显示执行的SQL可以完成预期的工作,但是每当需要将SQL字符串复制粘贴到SQL Server Management Studio中时,为了使其兼容,我们都必须对其进行重新排列。 在开始开发自己的应用程序以将其解析并重新排列为对ManagementStudio更友好的SQL之前,我想重申一下以前从未做过的事情- 我不愿意花时间在此上,以后再查找。 是否有一种廉
问题内容: 我有SQL Server 2008 R2,Windows 7 OS。 在服务器内,我有一个通过以下SQL语句创建的表。 在表中,我具有以下值: 我确实对数据库执行了以下SQL语句: 服务器给我以下错误消息: 转换nvarchar值“ 1”时转换失败。 数据类型为int。 我以为我的内部SQL首先执行并创建了一个临时表,因此它不包含在表中,然后SQL解析器将用于过滤临时表。 但是以上似乎
问题内容: 大家好,我想执行我的SQL语句,但是我在synatx上遇到麻烦,有人可以帮助我了解我做错了什么吗? 谢谢,阿什。 问题答案: 您需要解决的最重要的事情是使用查询参数,而不是动态地构建字符串。这将提高性能,维护和安全性。 此外,您想使用较新的强类型ADO.Net对象。确保为添加使用指令。 注意此代码中的语句。完成连接后,他们将 确保 您的连接已关闭。这很重要,因为数据库连接是有限且不受管
这是我的实体类 org.springframework.dao.DataIntegrityViolationException:不能执行语句;SQL[N/A];约束[created_at];嵌套异常是org.hibernate.exception.constraintViolationException:在org.springframework.orm.jpa.vendor.hibernatejp