1

I'm using EF Core and Devart's data provider library. I've hit an issue I can't figure out with handling user input errors smoothly. The error seems to be limited to adding a new entity to the context.

Scenario

  1. User inputs an invalid value in a field.
  2. Save changes is called and throws then displays error.
  3. Prompt user to fix the error.

After this if the error is fixed and save is called again (this is good data now), I get an exception "Transaction already exists" from the Devart data provider library.

StackTrace

at Devart.Data.Oracle.OracleConnection.BeginTransaction(IsolationLevel il) at Devart.Data.Oracle.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel) at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel) at  .BeginDbTransaction(IsolationLevel ) at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel) at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionWithNoPreconditions(IsolationLevel isolationLevel) at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransaction(IsolationLevel isolationLevel) at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransaction() at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.BeginTransaction() at

I tried to break out the transaction and handle it manually MSDN Transactions but I still get the same error.

    public bool SaveAllChanges()
    {
        var result = false;
        using (var transaction = _context.Database.BeginTransaction())
        {
            try
            {
                _context.Database.AutoTransactionsEnabled = false;
                _context.SaveChanges(true);
                transaction.Commit();
                result = true;
            }
            catch (Exception exc)
            {
                InvokeError(exc, "Error saving changes.");
                result = false;
            }
        }

        _context.Database.AutoTransactionsEnabled = true;
        _context.Database.CloseConnection();
        return result;

    }

How do I recover from a db error without scrapping all of the user's input? I would hate for that to be practice. I could be validating all the data going in but recovering from simple errors would be better.

Felix Castor
  • 1,598
  • 1
  • 18
  • 39

2 Answers2

0

After fussing around with this I found the magic sauce. This type of error only seems to come up when adding an object to the DB. It's as if the context doesn't dispose of the transaction on fail.

    public bool SaveAllChanges()
    {
        var result = false;
        _context.Database.AutoTransactionsEnabled = false;
        using (var transaction = _context.Database.BeginTransaction())
        {
            try
            {

                _context.SaveChanges(true);
                transaction.Commit();
                result = true;
            }
            catch (Exception exc)
            {
                transaction.Rollback(); <--------  Here.
                InvokeError(exc, "Error saving changes.");
                result = false;
            }
        }

        _context.Database.AutoTransactionsEnabled = true;
        _context.Database.CloseConnection();
        return result;

    }

If someone has a solution to where I don't need to handle the transaction in this way please post it.

Felix Castor
  • 1,598
  • 1
  • 18
  • 39
0

We cannot reproduce the "Transaction already exists" exception with the following code:

using (var _context = new MyContext())
{
    var entity = new MyEntity() { ID = 10, Name = "entry exceeds max length of the field" };
    _context.MyEntities.Add(entity);

    try
    {
        _context.SaveChanges(true); // error
    }
    catch (Exception ex)
    {
        //InvokeError(exc, "Error saving changes.");
    }

    entity.Name = "correct input";
    _context.SaveChanges(); // success
}

Please localize the issue in a small application and send us this project for reproducing.

Devart
  • 119,203
  • 23
  • 166
  • 186