Do użycia w moim bieżącym projekcie utworzyłem klasę, która pozwala mi wywoływać asynchronię SQL Server.Wywołanie wielu procedur składowanych SQL Server w transakcji
Mój kod wygląda następująco:
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");
}
}
}
Może to wyglądać zbyt dużo kodu, ale to pozwala mi nazwać jak tak:
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);
}
Powyższy kod działa dobrze dla mnie, Jestem w stanie wykonać każde połączenie asynchronicznie.
Problem, który mam teraz, to wykonywanie wielu połączeń jako transakcji - chciałbym zaktualizować 2 kody i dodać jedną nową
Normalnie chciałbym wywołać aktualizację, a następnie w drugiej aktualizacji obsługi handler, a w programie obsługi do drugiej aktualizacji chciałbym wywołać add, który zwróci nowy identyfikator.
Coś jak:
-UPDATE CODE
|-UPDATE CODE
|-ADD CODE (only this one return something)
Ale chciałbym zaprosić wszystkich tych, jako transakcji, więc jeśli dodać kod złamie aktualizacje byłoby wycofać.
Pytanie:
Czy to możliwe, aby wywołać wiele async kwerendy jako transakcję?
Czy mogę nazwać moje powyższe metody jako transakcję lub czy muszę utworzyć osobną metodę wywoływania moich procedur jako jedną? (Chciałbym tego uniknąć, ponieważ to tylko kopiowanie tego samego kodu z jednej metody do drugiej)
Chciałbym dodać, że używam .NET 3.5, więc oczekujcie, a inne fajne funkcje nie są opcją.
Niestety, aby zawrzeć wszystkie procedury w ramach jednej transakcji, należy wykonać je jeden po drugim. W przeciwnym razie będziesz miał transakcję na wykonanie. – LukeHennerley
LukeHennerly - Czy mógłbyś pomóc mi stworzyć metodę, która będzie nazywała wiele procedur jednym? Najlepiej byłoby, gdyby lista kodów była aktualizowana i dodawana do kodu jako parametry i oczywiście powinna być nazywana asynchronicznie jak wyżej: – Misiu