Как поместить эти вызовы в SqlTransaction?
У меня есть класс со всем моим кодом доступа к нему для моего приложения ASP.NET 4.0. В классе есть два метода, которые вставляют данные в базу данных. Я хочу включить эти вставки в SqlTransaction и откатить транзакцию, если одна из вставок не удалась. Однако я не уверен, как это сделать, из-за того, как я это кодировал. Вот мой код доступа к данным:
public class DBUtil
{
private static readonly string _connectionString;
static DBUtil()
{
_connectionString = WebConfigurationManager.ConnectionStrings["MooDB"].ConnectionString;
if (string.IsNullOrEmpty(_connectionString))
throw new Exception("Connection string not configured in Web.Config file");
}
public int InsertTrade(
string symbol,
string tradeSetupId,
int tradeTypeId,
decimal lotsPerUnit,
string chartTimeFrame,
decimal pctAccountRisked,
int? tradeGrade = null,
int? executionGrade = null,
int? MFEPips = null,
int? MAEPips = null
)
{
SqlCommand cmd = new SqlCommand("usp_InsertTrade");
// required parameters
cmd.Parameters.AddWithValue("@symbol", symbol);
cmd.Parameters.AddWithValue("@tradeSetupId", tradeSetupId);
cmd.Parameters.AddWithValue("@tradeTypeId", tradeTypeId);
cmd.Parameters.AddWithValue("@lotsPerUnit", lotsPerUnit);
cmd.Parameters.AddWithValue("@chartTimeFrame", chartTimeFrame);
cmd.Parameters.AddWithValue("@pctAccountRisked", pctAccountRisked);
// optional parameters
if (MAEPips.HasValue)
cmd.Parameters.AddWithValue("@MAEPips", MAEPips);
if (MFEPips.HasValue)
cmd.Parameters.AddWithValue("@MFEPips", MFEPips);
if (tradeGrade.HasValue)
cmd.Parameters.AddWithValue("@tradeGrade", tradeGrade);
if (executionGrade.HasValue)
cmd.Parameters.AddWithValue("@executionGrade", executionGrade);
return (InsertData(cmd, "trade"));
}
public int InsertOrder(
int tradeId,
int units,
string side,
decimal price,
decimal spread,
int strategyId,
string signalTypeId,
int brokerId,
string orderTypeId,
DateTime orderDateTime,
string comment,
int? accountId = null
)
{
SqlCommand cmd = new SqlCommand("usp_InsertOrder");
// required parameters
cmd.Parameters.Add(new SqlParameter("@tradeId", tradeId));
cmd.Parameters.Add(new SqlParameter("@units", units));
cmd.Parameters.Add(new SqlParameter("@side", side));
cmd.Parameters.Add(new SqlParameter("@price", price));
cmd.Parameters.Add(new SqlParameter("@spread", spread));
cmd.Parameters.Add(new SqlParameter("@strategyId", strategyId));
cmd.Parameters.Add(new SqlParameter("@signalTypeId", signalTypeId));
cmd.Parameters.Add(new SqlParameter("@brokerId", brokerId));
cmd.Parameters.Add(new SqlParameter("@orderTypeId", orderTypeId));
cmd.Parameters.Add(new SqlParameter("@orderDateTime", orderDateTime));
cmd.Parameters.Add(new SqlParameter("@comment", comment));
// optional parameters
if (accountId.HasValue)
cmd.Parameters.Add(new SqlParameter("@accountId", accountId));
return (InsertData(cmd, "order"));
}
private int InsertData(SqlCommand cmd, string tableName)
{
SqlConnection con = new SqlConnection(_connectionString);
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
int rc = -1;
try
{
con.Open();
rc = (int) cmd.ExecuteScalar();
}
finally
{
con.Close();
}
return rc;
}
}
Я получаю доступ к этому коду со своей страницы ASP.NET следующим образом:
int tradeId = DB.InsertTrade (
ddlSymbols.SelectedValue,
ddlTradeSetups.SelectedValue,
int.Parse(ddlTradeTypes.SelectedValue),
decimal.Parse(txtLotsPerUnit.Text),
ddlTimeFrames.Text,
decimal.Parse(txtAcctRisk.Text));
int orderId = DB.InsertOrder (
tradeId,
int.Parse(txtUnits.Text),
radSide.SelectedValue,
Decimal.Parse(txtEntryPrice.Text),
Decimal.Parse(txtSpread.Text),
int.Parse(ddlStrategies.SelectedValue),
"IE",
int.Parse(ddlBrokers.SelectedValue),
radSide.SelectedValue + radOrderType.SelectedValue,
DateTime.Parse(txtEntryDate.Text + " " + txtEntryTime.Text),
txtEntryComments.Text,
int.Parse(ddlAccounts.SelectedValue));
Что я хочу сделать, это обернуть вызовы со страницы ASP.NET в SqlTransaction. Каков наилучший способ сделать это? Придется ли мне несколько реорганизовать мой код?
Спасибо большое.
3 ответа
Использовать TransactionScope
Объект для размещения нескольких операторов в одной транзакции:
using (TransactionScope scope = new TransactionScope())
{
// Database call 1 - within transaction
// Database call 2 - within same transaction
scope.Complete(); // Commit the transaction, or face an automatic rollback
}
То, как вы вставляете новые данные в свое приложение, не сохраняет транзакции. Вы должны рефакторинг вашего кода все это в рамках одной транзакции и, возможно, соединения.
Быстрое и грязное исправление для этого состоит в том, чтобы создать соединение, открыть транзакцию и передать соединение каждому методу, вместо создания новых соединений внутри методов... После того, как все методы вызываются и не указываются исключения / ошибки, передайте транзакцию, в противном случае Откат это.
Я предполагаю, что t будет сложно, но я бы подумал об использовании некоторых ORM-картографов, таких как nHibernate. Зрелые картографы могут обрабатывать множество различных сценариев, в том числе и ваш.
Или используя класс SqlTransaction:
public void RunAsTransaction(string myConnString)
{
SqlConnection myConnection = new SqlConnection(myConnString);
myConnection.Open();
SqlCommand myCommand = myConnection.CreateCommand();
SqlTransaction myTrans;
myTrans = myConnection.BeginTransaction();
myCommand.Connection = myConnection;
myCommand.Transaction = myTrans;
try
{
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')";
myCommand.ExecuteNonQuery();
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')";
myCommand.ExecuteNonQuery();
myTrans.Commit();
}
catch(Exception e)
{
myTrans.Rollback();
}
finally
{
myConnection.Close();
}
}