如何将这些调用放入SqlTransaction中?

3

我有一个包含所有数据访问代码的类,用于我的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个回答

4
使用 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
}

哇,那真是个快速的回答。感谢你今天的帮助。 - Mark Allison
任何时候,@Mark... 很高兴能帮到你 :) - Oded

0

或者使用 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();
}

}


0

你的应用程序插入新数据的方式不是事务安全的。 你应该重构你的代码,将所有操作放在同一个事务和连接中。

快速而简单的解决方法是创建一个连接,打开事务并将连接传递给每个方法,而不是在方法内部创建新连接... 当所有方法被调用且没有指示异常/错误时,提交事务,否则回滚它。

我认为这可能有些困难,但我建议使用一些ORM映射器,如nHibernate。 成熟的映射器可以处理许多不同的情况,包括你的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接