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 中。做这个的最好方式是什么?我需要重构我的代码吗?

非常感谢。

4

3 回答 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
}
于 2010-11-08T13:58:29.477 回答
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();
}

}

于 2010-11-08T14:50:17.487 回答
0

您在应用程序中插入新数据的方式不是事务保存。您应该在同一个事务和可能的连接中重构您的所有代码。

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

我认为这很困难,但我会考虑使用一些 ORM 映射器,如 nHibernate。成熟的映射器可以处理很多不同的场景,包括你的。

于 2010-11-08T14:10:55.410 回答