简体   繁体   English

实体框架和SQL Server保存点

[英]Entity Framework and SQL Server Savepoints

I asked a different question about Nested Transactions and the answer to my question educated me enough to help me realize I was asking the question poorly. 我问一个不同的问题有关嵌套事务和回答我的问题教育了我足够的帮助,我意识到我是问这个问题不好。 So here's a better question. 所以这是一个更好的问题。

How can I effectively implement SQL Server Savepoints ( link 1 , link 2 ) with a DAL built upon Entity Framework 4.0? 如何使用基于Entity Framework 4.0构建的DAL有效地实现SQL Server保存点( 链接1链接2 )?

I would LIKE to write the following code and have it work in a way that SQL Server's SAVEPOINTS 我希望编写以下代码,并使它以SQL Server SAVEPOINTS的方式工作

public void Bar()
{
  using (var ts = new TransactionScope())
  {
    var ctx = new Context();
    DoSomeStuff(ctx);

    bool isSuccessful;

    using (var spA = new SavePoint("A")) // <-- this object doesn't really exist, I don't think
    {
      isSuccessful = DoSomeOtherStuff(ctx);
      if (isSuccessful)
        spA.Complete(); // else rollback bo prior to the beginning of this using block
    }

    Log(ctx, isSuccessful);

    ts.Complete();
  }
}

Is there such a way to do anything even close to resembling this, or something else that plays nicely with EF4? 有没有办法做类似于此的事情,或者可以与EF4配合使用? (we use custom self-tracking POCO entities) (我们使用自定义自跟踪POCO实体)

This isn't quite a full answer, but I suspect something like this might be going down the right path. 这不是一个完整的答案,但是我怀疑这样的事情可能会走上正确的道路。 My problem is that I'm not entirely sure how to get a SqlTransaction while in a TransactionScope . 我的问题是我不确定在TransactionScope中如何获取SqlTransaction

/// <summary>
/// Makes a code block transactional in a way that can be partially rolled-back. This class cannot be inherited.
/// </summary>
/// <remarks>
/// This class makes use of SQL Server's SAVEPOINT feature, and requires an existing transaction.
/// If using TransactionScope, utilize the DependentTransaction class to obtain the current Transaction that this class requires.
/// </remarks>
public sealed class TransactionSavePoint : IDisposable
{
    public bool IsComplete { get; protected set; }
    internal SqlTransaction Transaction { get; set; }
    internal string SavePointName { get; set; }

    private readonly List<ConnectionState> _validConnectionStates = new List<ConnectionState>
                                                                        {
                                                                            ConnectionState.Open
                                                                        };

    public TransactionSavePoint(SqlTransaction transaction, string savePointName)
    {
        IsComplete = false;
        Transaction = transaction;
        SavePointName = savePointName;

        if (!_validConnectionStates.Contains(Transaction.Connection.State))
        {
            throw new ApplicationException("Invalid connection state: " + Transaction.Connection.State);
        }

        Transaction.Save(SavePointName);
    }

    /// <summary>
    /// Indicates that all operations within the savepoint are completed successfully.
    /// </summary>
    public void Complete()
    {
        IsComplete = true;
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        if (!IsComplete)
        {
            Transaction.Rollback(SavePointName);
        }
    }
}

This would be consumed as such, very similarly to a TransactionScope: 这样就可以使用它,非常类似于TransactionScope:

SqlTransaction myTransaction = Foo();

using (var tsp = new TransactionSavePoint(myTransaction , "SavePointName"))
{
  try
  {
    DoStuff();
    tsp.Complete
  }
  catch (Exception err)
  {
    LogError(err);
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM