我有一个带有多个属性的对象,每个属性都由单独的SQL select语句填充。我想同时执行select语句,但是等待返回整个对象,直到每个属性都有数据为止。我对使用C#进行异步处理非常陌生,但是我很难将其包裹起来。这是我如何同步完成此操作的示例。
public MyObj GetMyObj()
{
MyObj obj = new MyObj();
using (SqlConnection con = new SqlConnection("connectionString"))
{
con.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = con;
cmd.CommandText = "Select ...";
cmd.CommandType = CommandType.Text;
obj.Prop1 = cmd.ExecuteScalar();
}
}
using (SqlConnection con = new SqlConnection("connectionString"))
{
con.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = con;
cmd.CommandText = "Select ...";
cmd.CommandType = CommandType.Text;
obj.Prop2 = cmd.ExecuteScalar();
}
}
return obj;
}
理想情况下,我想为每个选择块创建任务方法,并等待完成后返回完整的对象(我的基本理解来自Microsoft Async article):
public MyObj GetMyObj()
{
MyObj obj = new MyObj();
var prop1Task = GetProp1();
var prop2Task = GetProp2();
var allTasks = new List<Task>{prop1Task, prop2Task};
while (allTasks.Any())
{
Task finished = await Task.WhenAny(allTasks);
if (finished == prop1Task)
{
allTasks.Remove(prop1Task);
obj.Prop1 = await prop1Task;
} else if (finished == prop2Task)
{
allTasks.Remove(prop2Task);
obj.Prop2 = await prop2Task;
} else
allTasks.Remove(finished);
}
return obj;
}
private async Task<int> GetProp1()
{
int prop1 = 0;
using (SqlConnection con = new SqlConnection("connectionString"))
{
con.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = con;
cmd.CommandText = "Select ...";
cmd.CommandType = CommandType.Text;
prop1 = cmd.ExecuteScalar();
}
}
return prop1;
}
在构建GetProp1()
方法时,我收到一个智能提示,即“ 该异步方法缺少'await'运算符,将同步运行。
我可以正确执行各个“ GetProp”方法吗?智能警告是否错误?我正在执行几个select语句,因此将此操作更改为异步运行将大大提高性能。
在此先感谢您的帮助!
答案 0 :(得分:1)
GetProp1
中没有任何异步执行。警告的含义与所讲的完全相同。有一个标记为async
的方法不会异步执行任何操作,因此它将同步执行。重写GetPropX
方法以在SqlConnection
/ SqlCommand
上使用异步方法。
private async Task<int> GetProp1()
{
int prop1 = 0;
using (SqlConnection con = new SqlConnection("connectionString"))
{
await con.OpenAsync();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = con;
cmd.CommandText = "Select ...";
cmd.CommandType = CommandType.Text;
prop1 = await cmd.ExecuteScalarAsync();
}
}
return prop1;
}
也就是说,如果各种select语句都针对同一个数据库执行,则可以一次执行多个语句,请使用ExecuteReader
和NextResult
。
像这样...
private async Task<MyObj> GetMyObjAsync()
{
MyObj obj = new MyObj();
using (SqlConnection con = new SqlConnection("connectionString"))
{
await con.OpenAsync();
string sqlStatements = @"
SELECT Prop1 FROM Table1;
SELECT Prop2 FROM Table2;
SELECT Prop3 FROM Table3;
--etc";
using (SqlCommand cmd = new SqlCommand(sqlStatements, con))
using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
obj.Prop1 = Convert.ToInt32(reader["Prop1"]);
}
await reader.NextResultAsync();
if (await reader.ReadAsync())
{
obj.Prop2 = Convert.ToInt32(reader["Prop2"]);
}
await reader.NextResultAsync();
if (await reader.ReadAsync())
{
obj.Prop3 = Convert.ToInt32(reader["Prop3"]);
}
// etc...
}
}
return obj;
}
这样,您只有一个与数据库的连接,而不必为MyObj
上的每个属性创建单独的连接。