Mis*_*siu 13 c# sql-server asynchronous transactions .net-3.5
为了在我当前的项目中使用,我创建了一个允许我调用SQL Server异步的类.
我的代码看起来像这样:
internal class CommandAndCallback<TCallback, TError>
{
public SqlCommand Sql { get; set; }
public TCallback Callback { get; set; }
public TError Error { get; set; }
}
class MyCodes:SingletonBase<MyCodes>
{
private static string _connString = @"Data Source=MyDB;Initial Catalog=ED;Integrated Security=True;Asynchronous Processing=true;Connection Timeout=0;Application Name=TEST";
private MyCodes() { }
public void SetSystem(bool production)
{
_connString =
string.Format(@"Data Source=MyDB;Initial Catalog={0};Integrated Security=True;Asynchronous Processing=true;Connection Timeout=0;Application Name=TEST", production ? "ED" : "TEST_ED");
}
public void Add(string newCode, Action<int> callback, Action<string> error)
{
var conn = new SqlConnection(_connString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = @"ADD_CODE";
cmd.Parameters.Add("@NEW", SqlDbType.NVarChar).Value = newCode;
cmd.Parameters.Add("@NewId", SqlDbType.Int).Direction = ParameterDirection.Output;
try
{
cmd.Connection.Open();
}
catch (Exception ex)
{
error(ex.ToString());
return;
}
var ar = new CommandAndCallback<Action<int>, Action<string>> { Callback = callback, Error = error, Sql = cmd };
cmd.BeginExecuteReader(Add_Handler, ar, CommandBehavior.CloseConnection);
}
private static void Add_Handler(IAsyncResult result)
{
var ar = (CommandAndCallback<Action<int>, Action<string>>)result.AsyncState;
if (result.IsCompleted)
{
try
{
ar.Sql.EndExecuteReader(result);
ar.Callback(Convert.ToInt32(ar.Sql.Parameters["@NewId"].Value));
}
catch (Exception ex)
{
ar.Error(ex.Message);
}
}
else
{
ar.Error("Error executing SQL");
}
}
public void Update(int codeId, string newCode, Action callback, Action<string> error)
{
var conn = new SqlConnection(_connString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = @"UPDATE_CODE";
cmd.Parameters.Add("@CODE_ID", SqlDbType.Int).Value = codeId;
cmd.Parameters.Add("@NEW", SqlDbType.NVarChar).Value = newCode;
try
{
cmd.Connection.Open();
}
catch (Exception ex)
{
error(ex.ToString());
return;
}
var ar = new CommandAndCallback<Action, Action<string>> { Callback = callback, Error = error, Sql = cmd };
cmd.BeginExecuteReader(Update_Handler, ar, CommandBehavior.CloseConnection);
}
private static void Update_Handler(IAsyncResult result)
{
var ar = (CommandAndCallback<Action, Action<string>>)result.AsyncState;
if (result.IsCompleted)
{
try
{
ar.Sql.EndExecuteReader(result);
ar.Callback();
}
catch (Exception ex)
{
ar.Error(ex.Message);
}
}
else
{
ar.Error("Error executing SQL");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这可能看起来像是太多的代码,但它让我这样称呼它:
private void Add_Click(object sender, EventArgs e)
{
MyCodes.Instance.Add("Test",Success,Error)
}
private void Success(int newId)
{
MessageBox.Show(newId.ToString(), "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void Error(string error)
{
MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码对我来说很好,我能够做每个调用异步.
我现在遇到的问题是作为交易进行多次调用 - 我想更新2个代码并添加一个新代码.
通常我会调用update,然后在成功处理程序中调用第二次更新,并在处理程序中进行第二次更新,我会调用add将返回新的id.
就像是:
-UPDATE CODE
|-UPDATE CODE
|-ADD CODE (only this one return something)
Run Code Online (Sandbox Code Playgroud)
但是我想把所有这些都称为事务,所以如果添加代码会破坏更新会回滚.
题:
是否可以将多个异步查询作为事务调用?
我可以将上述方法称为事务,还是必须创建单独的方法来将我的过程称为一个?(我想避免这个,因为它只是将相同的代码从一个方法复制到另一个方法)
我想补充一点,我使用.NET 3.5所以等待和其他不错的功能不是一个选项.
use*_*316 18
string cnnString =WebConfigurationManager.ConnectionStrings["MyString"].ConnectionString;
SqlConnection cnn = new SqlConnection(cnnString);
SqlTransaction transaction;
cnn.Open();
transaction = cnn.BeginTransaction();
try
{
// Command Objects for the transaction
SqlCommand cmd1 = new SqlCommand("sproc1", cnn);
SqlCommand cmd2 = new SqlCommand("sproc2", cnn);
cmd1.CommandType = CommandType.StoredProcedure;
cmd2.CommandType = CommandType.StoredProcedure;
cmd1.Parameters.Add(new SqlParameter("@Param1", SqlDbType.NVarChar, 50));
cmd1.Parameters["@Param1"].Value = paramValue1;
cmd1.Parameters.Add(new SqlParameter("@Param2", SqlDbType.NVarChar, 50));
cmd1.Parameters["@Param2"].Value = paramValue2;
cmd2.Parameters.Add(new SqlParameter("@Param3", SqlDbType.NVarChar, 50));
cmd2.Parameters["@Param3"].Value = paramValue3;
cmd2.Parameters.Add(new SqlParameter("@Param4", SqlDbType.NVarChar, 50));
cmd2.Parameters["@Param4"].Value = paramValue4;
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
transaction.Commit();
}
catch (SqlException sqlEx)
{
transaction.Rollback();
}
finally
{
cnn.Close();
cnn.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
对的,这是可能的.只需SqlConnection.BeginTransaction
在第一次调用之前调用,就可以将返回的SqlTransaction
对象分配给SqlCommand.Transaction
链中的每个对象并SqlTransaction.Commit()
在最后调用.