Entity Framework и точки сохранения SQL Server

Я задал другой вопрос о вложенных транзакциях, и ответ на мой вопрос дал мне достаточно знаний, чтобы помочь мне понимаю, что я плохо задал вопрос. Так вот вопрос лучше.

Как эффективно реализовать точки сохранения SQL Server (ссылка 1, ссылка 2) с DAL, построенным на Entity Framework 4.0?

Я ХОЧУ написать следующий код и заставить его работать так, чтобы SAVEPOINTS SQL Server

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();
  }
}

Есть ли такой способ сделать что-то хотя бы похожее на это или что-то еще, что хорошо работает с EF4? (мы используем настраиваемые объекты POCO с самостоятельным отслеживанием)


person Jaxidian    schedule 08.08.2011    source источник


Ответы (1)


Это не совсем полный ответ, но я подозреваю, что что-то подобное может идти по правильному пути. Моя проблема в том, что я не совсем уверен, как получить 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);
        }
    }
}

Это будет использоваться как таковое, очень похожее на TransactionScope:

SqlTransaction myTransaction = Foo();

using (var tsp = new TransactionSavePoint(myTransaction , "SavePointName"))
{
  try
  {
    DoStuff();
    tsp.Complete
  }
  catch (Exception err)
  {
    LogError(err);
  }
}
person Jaxidian    schedule 09.08.2011
comment
Я отмечаю это как ответ, так как это лучшее, что я смог найти. - person Jaxidian; 18.08.2011