Für die Verwendung in meinem aktuellen Projekt habe ich eine Klasse erstellt, mit der ich SQL Server async aufrufen kann.Mehrere gespeicherte SQL Server-Prozeduren in einer Transaktion aufrufen
Mein Code sieht wie folgt aus:
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");
}
}
}
Das ist wie zu viel von Code aussehen kann, aber es lässt mich nennen wie so:
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);
}
Above-Code für mich ganz gut funktioniert, Ich kann jeden Anruf asynchron ausführen.
Problem, das ich gerade habe, ist, mehrere Anrufe als Transaktion zu tun - ich möchte 2 Codes aktualisieren und eine neue hinzufügen.
Normalerweise würde ich update aufrufen, dann in der success handler call zweiten update, und in der handler zu zweiten update würde ich hinzufügen hinzufügen, die neue id zurückgeben würde.
Etwas wie:
-UPDATE CODE
|-UPDATE CODE
|-ADD CODE (only this one return something)
Aber ich möchte all jene, die als Transaktion nennen, so Code, wenn hinzufügen würde Updates brechen würde Rollback.
Frage:
Ist es möglich, mehrere asynchrone Abfragen als eine Transaktion zu nennen?
Kann ich meine oben genannten Methoden als Transaktion aufrufen oder muss ich eine separate Methode erstellen, um meine Prozeduren als eine aufzurufen? (Ich möchte dieses vermeiden, weil es nur den gleichen Code von einer Methode zu einem anderen kopiert)
Ich möchte hinzufügen, dass ich .NET 3.5 verwende, also warten und andere nette Eigenschaften sind keine Wahl.
Leider müssen Sie alle Ihre Prozeduren in einer einzigen Transaktion umwandeln, die Sie nacheinander ausführen müssen. Sie werden sonst am Ende eine Transaktion pro Ausführung haben. – LukeHennerley
LukeHennerly - Könnten Sie mir helfen, eine Methode zu entwickeln, die mehrere Prozeduren als eine bezeichnet? Im Idealfall würde es Liste der Codes zu aktualisieren und Code als Parameter hinzufügen und natürlich sollte es async wie oben genannt werden – Misiu