Introduction

Microsoft .NET 4.5 introduced new "async and await" methods to provide an easy way of implementing asynchronisity using .NET "Task" objects.

This allows developers to make async calls more flexibly, as opposed to standard threading/callback methods.

In this article i've built a demo to show how this can be applied to build easy to use SQL functions which can be called async.

Getting started

For this article we shall be using the .NET SQL Client library for connecting to a Microsoft SQL Server database, however the same methodology of wrapping up code in a task can be used with any other type of connection.

In this example we will wrap our code which connects to the database to get data into a function which returns a "Task" object based on the data type we require.

Building Asynchronous Task Functions

We start by building the initial wrapper which returns a task object. We shall be returning a dataset in this example.

Side note: Any data type can be returned with task objects, as such you could return a string, integer or a custom class.

The following is the basic wrapper for our function. This bit of code will return a task object based on the datatype, with a section to add our own code to build and return the dataset.

public Task<DataSet> GetDataSetAsync(string sConnectionString, string sSQL)
{
return Task<DataSet>.Factory.StartNew(() =>
{
//MY CODE HERE
});
}

We can now insert code which connects to the server to get data based on a query into this function.

Example 1: Function to fill a dataset based on the SQL query.

In this example code has been added to the body of the function which uses a standard SQL connection string and objects from the System.Data.SQLClient .NET library to connect to the database and fill a dataset based on the query.

Once the dataset has been filled the code will then return the dataset using a standard "return" call.

public Task<DataSet> GetDataSetAsync(string sConnectionString, string sSQL, params SqlParameter[] parameters)
{
//Return task based on datatype
return Task.Run(() =>
{
using (var newConnection = new SqlConnection(sConnectionString))
using (var mySQLAdapter = new SqlDataAdapter(sSQL, newConnection))
{
mySQLAdapter.SelectCommand.CommandType = CommandType.Text;
if (parameters != null) mySQLAdapter.SelectCommand.Parameters.AddRange(parameters); DataSet myDataSet = new DataSet();
mySQLAdapter.Fill(myDataSet);
return myDataSet;
}
});
}

We can now call this function asynchronously to return a dataset of data based on our query.

Example 2: Function to execute a command, passing back the rows affected.

In this example, we have changed the data type to integer, as we simply want to pass back the rows affected for the result of this function.

public Task<int> ExecuteAsync(string sConnectionString, string sSQL, params SqlParameter[] parameters)
{
return Task.Run(() =>
{
using (var newConnection = new SqlConnection(sConnectionString))
using (var newCommand = new SqlCommand(sSQL, newConnection))
{
newCommand.CommandType = CommandType.Text;
if (parameters != null) newCommand.Parameters.AddRange(parameters); newConnection.Open();
return newCommand.ExecuteNonQuery();
}
});
}

Further to this, there are existing async task functions on the SqlCommand object which can be used to simplify the function further.

public async Task<int> ExecuteAsync(string sConnectionString,
string sSQL, params SqlParameter[] parameters)
{
using (var newConnection = new SqlConnection(sConnectionString))
using (var newCommand = new SqlCommand(sSQL, newConnection))
{
newCommand.CommandType = CommandType.Text;
if (parameters != null) newCommand.Parameters.AddRange(parameters); await newConnection.OpenAsync().ConfigureAwait(false);
return await newCommand.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}

We can use this function to execute SQL and get the rows affected.

Calling Asynchronous Task Functions

Now that we have an async function to get data from SQL we can now call this asynchronously using the async\await clause from any method.

To call the function to get data we start by adding "async" into the method declaration.

private async <type> MyMethod()

Now that our method is an "async" method we can use the "await" option on the tasks returned from our SQL functions.

Execute Task Function

To execute task functions you need to add "await" before the function call.

This will execute the function, and return the "Result" to the variable should one be specified.

private async Task GetSomeData(string sSQL)
{
//Use Async method to get data
DataSet results = await GetDataSetAsync(sConnectionString, sSQL, sqlParams); //Populate once data received
grdResults.DataSource = results.Tables[0];
}

Variables do not need to be specified. You can call the function using "await" which will run the task without retrieving a result.

private async Task ExecuteSomeData(string sSQL)
{
//Use Async method to get data
await ExecuteAsync(sConnectionString, sSQL, sqlParams);
}

The "await" option can be specified multiple times if you need to make other asyncronous calls.

You can make GUI updates before and after the "await" command, as it is only the await command which is run asynchronously.

The simplest use of "async/await" is to use the "await" option, then continue with your code afterwards.

However the .NET task object provides other methods of continuation once the asynchronous task has completed.

Running Multiple Tasks/Chaining Tasks

If you need to run multiple SQL operations there are a few ways of achieving this.

Specifing Tasks As Variables Then Running Together

You can specify a number of commands as variables and run them all at once asynchronously, then get the results as necessary.

This can be achieved by setting up your tasks as variables.

Once setup you will need to add them into an array then use the "Task.WhenAll" to run all the tasks asynchronously.

You can then access the results on the task object after completion.

//Setup tasks
Task<int> ExecuteTask1 = database.ExecuteAsync(sConnectionString, sExecuteSQL1, sqlParams);
Task<int> ExecuteTask2 = database.ExecuteAsync(sConnectionString, sExecuteSQL2, sqlParams);
Task<int> ExecuteTask3 = database.ExecuteAsync(sConnectionString, sExecuteSQL3, sqlParams);
//Add to array
Task<int>[] Tasks = new Task<int>[] { ExecuteTask1, ExecuteTask2, ExecuteTask3 };
//Run all
await Task.WhenAll(Tasks);
//Get results
int iRowsAffected = Tasks[0].Result + Tasks[1].Result + Tasks[2].Result;

Calling Other Async Tasks With "ContinueWith"

Another method of chaining the tasks together is using the "ContinueWith" method on the task object returned by your SQL function.

In this example we start by running an execute task function, then once complete we run a select task function to get a dataset to a variable.

DataSet results = await database.ExecuteAsync(sConnectionString, sExecuteSQL, sqlParams).ContinueWith(t => database.GetDataSetAsync(sConnectionString, sGetSQL, sqlParams)).Result;

Calling Standard Methods With "ContinueWith"

You can call a standard method on the "ContinueWith" method.

In this example we use "ContinueWith" on the task object to pass the data through to a separate method.

private async Task RunSQLQuery(string sSQL)
{
//Use await method to get data
await GetDataSetAsync(sConnectionString, sSQL, sqlParams).ContinueWith(t => PopulateResults(t.Result));
}
private void PopulateResults(DataSet results)
{
//Do something with results
}

WARNING: When using "ContinueWith" in this way this will continue the async thread, meaning that if you intend to update GUI components such as a grid or textbox control you may encounter the error:

Cross-thread operation not valid: Control MyControl accessed from a thread other than the thread it was created on.

In cases like this you can invoke the method from within the "ContinueWith" which will allow for GUI updates.

await database.GetDataSetAsync(sConnectionString, sSQL, sqlParams).ContinueWith(t => this.Invoke((Action)(() => { PopulateResultsToScreen(t.Result); })));

异步数据库查询 Z的更多相关文章

  1. Python中实现异步并发查询数据库

    这周又填了一个以前挖下的坑. 这个博客系统使用Psycopy库实现与PostgreSQL数据库的通信.前期,只是泛泛地了解了一下SQL语言,然后就胡乱拼凑出这么一个简易博客系统. 10月份找到工作以后 ...

  2. 第九十九天上课 PHP TP框架 数据库查询和增加

    在Model文件夹下创建模型,文件命名规则 : 表名Model.class.php <?php namespace Home\Model; use Think\Model; class yong ...

  3. 转 zabbix 优化方法 以及 后台数据库查询方法 两则

    ############sample 1 https://blog.51cto.com/sfzhang88/1558254 如何从Zabbix数据库中获取监控数据 sfzhang关注6人评论40627 ...

  4. 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。

    最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...

  5. [转]C#反射,根据反射将数据库查询数据和实体类绑定,并未实体类赋值

    本文来自:http://www.cnblogs.com/mrchenzh/archive/2010/05/31/1747937.html /****************************** ...

  6. 各数据库查询前N条记录的SQL语句

    sql在不同数据库查询前几条数据 1. ORACLE SELECT * FROM TABLE_NAME WHERE ROWNUM <= N;  HQL: from table_name t or ...

  7. Atitit  DbServiceV4qb9 数据库查询类库v4 新特性

    Atitit  DbServiceV4qb9 数据库查询类库v4 新特性     V4新特性 安全特性,屏蔽了executeUpdate,使用v2版 Sql异常转换,特别转换了DuplicateEnt ...

  8. C#与mysql做ASP.NET网页数据库查询速度测试

    两种方法是:1,使用mysql数据库的存储过程:2,C#编码,做网页后台与mysql数据库连接,前台测试显示测试过结果下面我将分别讲解两种方法的具体实现. 1,使用mysql数据库的存储过程插入万条大 ...

  9. mysql数据库查询pdo的用法

    最早的php对mysql数据库查询是mysql和mysqli方法,后来php的新版本进一步封住了该方法,于是又pdo,抛开php框架,使用pdo查询数据,使用也是相当简便 <?php ini_s ...

随机推荐

  1. 用纯Css作三角形

    <style> //向上三角形 .triangle_up{ width:0; height:0; border-left:30px solid transparent; border-ri ...

  2. git中Member设置为Developer也可以的

    之前说Member至少要设置为master,或者owner才行,昨天发现依然可以设置为developer. 因为有个位置可以设置Developers can push,√上就可以了. 比如,我不希望大 ...

  3. 微信公众平台如何获取用户的OpenID(一)

    如何获取用户的OpenID,对于微信开发模式下的开发来说,那就是一个非常简单的小功能了.简单介绍一下我是怎样去获取OpenID的. 微信服务器与公众账号服务器交互的信息可以分为3类:请求消息.事件和响 ...

  4. Django+python+BeautifulSoup垂直搜索爬虫

    http://blog.sina.com.cn/s/blog_709475a10100wmln.html

  5. jquery替换URL参数值

    由于经常会用到替换URL参数值,而网上写的方法代码都太长了,所以在这里写了一个简单的方法,供大家使用. 说明: reLoad(参数名,参数值) function reLoad(p, v) { var ...

  6. The data is said to include information from networks

    The data is said to include information from networks as well as from individual computers and smart ...

  7. Bootstrap框架基础

    特点:写非常少的代码 即可实现多终端的页面适配 ☑  简单灵活可用于架构流行的用户界面和交互接口的html.css.javascript工具集. ☑  基于html5.css3的bootstrap,具 ...

  8. Android中Service的使用

    我个人的理解是:我们平时使用的android系统的app的后台应用,就是这个原理 可以利用Service实现程序在后台运行,依照这个原理,可以通过Service来实现关键代码的运行与实现. <一 ...

  9. 【LeetCode OJ】Path Sum II

    Problem Link: http://oj.leetcode.com/problems/path-sum-ii/ The basic idea here is same to that of Pa ...

  10. Sublime Text 3安装插件指南

    Sublime Text已经很用得很广泛,一般普通的功能已经够用,加入一些插件能些许加快开发. 安装 Package Control 有了插件控制器Package Control安装起来就很轻松了. ...