TFireDACTransactionAdapter incorrect work with nested firedac transactions

Issue #298 resolved
Inkvizi created an issue
destructor TDriverTransactionAdapter<T>.Destroy;
begin
  if InTransaction then
    Rollback;
  inherited Destroy;
end;
function TFDCustomTransaction.GetActive: Boolean;
begin
  Result := (FTransactionIntf <> nil) and FTransactionIntf.Active;
end;
function TFDPhysTransaction.GetActive: Boolean;
begin
  Result := FSavepoints.Count > 0;
end;

If IDBTransaction will be nested transaction and goes out of scope then TFireDACTransactionAdapter can Rollback not his transaction. Because nested FireDacTransaction will be active until the main transaction is commited or rollback.

Test:

procedure TestTDataBaseTransaction.TestCommit;
var
  LEntity: TTestTableEntity;
  LRecordCount: Integer;
  LDBTransaction: IDBTransaction;
  LDBTransactionNested: IDBTransaction;
begin
  LRecordCount := FDataBaseForCheck.Session.ExecuteScalar<Integer>(__SELECT_COUNT_QUERY, []);
  Assert.AreEqual(0, LRecordCount);
  LDBTransaction := FDataBase.Session.BeginTransaction;
  try
    LDBTransaction.TransactionName := 'TestTransactionName';
    LDBTransactionNested := FDataBase.Session.BeginTransaction;
    try
      LDBTransactionNested.TransactionName := 'TestNestedTransactionName';
      LEntity := TTestTableEntity.Create;
      try
        LEntity.Name := 'TestTransactionComit';
        FDataBase.Session.Insert(LEntity);
        LRecordCount := FDataBaseForCheck.Session.ExecuteScalar<Integer>(__SELECT_COUNT_QUERY, []);
        Assert.AreEqual(0, LRecordCount);
        LDBTransactionNested.Commit;
        LRecordCount := FDataBaseForCheck.Session.ExecuteScalar<Integer>(__SELECT_COUNT_QUERY, []);
        Assert.AreEqual(0, LRecordCount);
      finally
        LEntity.Free;
      end;
    finally
      LDBTransactionNested := nil;
    end;
    LDBTransaction.Commit; //<==== Error Transaction must be active
    LRecordCount := FDataBaseForCheck.Session.ExecuteScalar<Integer>(__SELECT_COUNT_QUERY, []);
    Assert.AreEqual(1, LRecordCount);
  finally
    LDBTransaction := nil;
  end;
end;

Comments (1)

  1. Log in to comment