Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollback #4

Closed
Twodio opened this issue Jul 19, 2019 · 6 comments
Closed

Rollback #4

Twodio opened this issue Jul 19, 2019 · 6 comments

Comments

@Twodio
Copy link

Twodio commented Jul 19, 2019

Hi there, how does rollback occours in your code ?
Lets say i have a table with the following fields:

-Id (Int, Key, Auto Increment)
-Name(Nvarchar, Constraint, Not Null)
-Age(Int, Null)

When i try to insert two people in row like.

using(var uow = repositoryFactory.Create(true)){
    uow.Execute(new AddPersonCommand(PersonInstanceOne));
    uow.Execute(new AddPersonCommand(PersonInstanceOne));
    uow.Commit();
}

The first query executes without any throuble as it should, but after the second query where i try to insert an existing constraint i get the exception but the commit accours for the first query.

My repository's execute method looks like this:

public void Execute(ICommand command){
        if (command.RequiresTransaction && _transaction==null)
            throw new Exception($"Error")

        try{
            command.Execute(_connection, _transaction)
        } Catch(SqlClient.SqlException ex
            Debug.WriteLine($"Error: {ex.Message}")
        }
}
@petrhaus
Copy link
Collaborator

petrhaus commented Jul 19, 2019

Hi,
the rollback is handled automatically.
Can you please add the whole AddPersonCommand class?
If you have correctly inherited from ICommand, the Execute method should be:
void Execute(IDbConnection connection, IDbTransaction transaction)
Example here: https://github.com/outmatic/Dapper.UnitOfWork/blob/master/src/Dapper.UnitOfWork/Dapper.UnitOfWork.Example/Data/Commands/AddCustomerCommand.cs

@Twodio
Copy link
Author

Twodio commented Jul 19, 2019

It's all VB

Imports System.Threading
Imports Dapper
Imports RepositoryTest.DataMine

Public Class AddPersonCommand
    Implements ICommand, IAsyncCommand

    Private Const statement As String = "INSERT INTO People(Name, Age) VALUES(@Name, @Age)"
    Private ReadOnly Property _Person As Person

    Public ReadOnly Property RequiresTransaction As Boolean Implements IAsyncCommand.RequiresTransaction, ICommand.RequiresTransaction
        Get
            Return True
        End Get
    End Property

    Public Sub New(ByVal Person As Person)
        _Person = Person
    End Sub

    Public Sub Execute(connection As IDbConnection, transaction As IDbTransaction) Implements ICommand.Execute
        connection.Execute(statement, _Person, transaction)
    End Sub

    Public Function ExecuteAsync(connection As IDbConnection, transaction As IDbTransaction, Optional cancelationToken As CancellationToken = Nothing) As Task Implements IAsyncCommand.ExecuteAsync
        Return connection.ExecuteAsync(statement, _Person, transaction)
    End Function
End Class

@petrhaus
Copy link
Collaborator

The command looks ok, but where is the following code from?
Did you notice that the SqlException is handled without being rethrown?

public void Execute(ICommand command){
        if (command.RequiresTransaction && _transaction==null)
            throw new Exception($"Error")

        try{
            command.Execute(_connection, _transaction)
        } Catch(SqlClient.SqlException ex
            Debug.WriteLine($"Error: {ex.Message}")
        }
}

@Twodio
Copy link
Author

Twodio commented Jul 19, 2019

Understood, since your example had only one annotation for the mandatory Commit i thought the Rollback was automatic as you said, as if it doesn't need an extra Try...Catch block, it got me confused, that's why i was wondering what did i do wrong. And sorry for the late answer even after taking your time, i was driving back home.

UnitOfWork(Repository) Execute method, reverted back to its inital state.

Public Sub Execute(command As ICommand) Implements IUnitOfWork.Execute
        If command.RequiresTransaction And IsNothing(_transaction) Then
            Throw New Exception($"Error")
        End If
        command.Execute(_connection, _transaction)
    End Sub

And the implementation of the repository within the Main method of a console application:

Using uow As UnitOfWork = repository.Create(True)
            Try
                uow.Execute(New AddPersonCommand(New Person With {.Name = "Jane Smith", .Age = 24}))
                uow.Execute(New AddPersonCommand(New Person With {.Name = "Jane Smith", .Age = 24}))
                uow.Commit()
            Catch ex As Exception
                uow.RollBack()
            End Try
        End Using

I also noticed that your code implements an exception handler, is he responsible for rolling back the transaction and/or avoiding the commit ?

@petrhaus
Copy link
Collaborator

Since the transaction is explicitly started, if not committed it gets rolled back. There is no need to issue a rollback in a catch block. Of course if you have modified the original code, things may not work as expected :-)
The exception handler is meant to catch sql transient exceptions and issue retries.

@Twodio
Copy link
Author

Twodio commented Jul 19, 2019

Yeah, i work with more complex and bulk data and debug is the only thing that keeps me on track(most of times). I was using an old implementation and not much of eficient as i expected, was just a hack apparently and now i'm replacing the code i have because i'm about to add more functionality and right now Dapper is the only thing working with my models. Thanks for the feedback man.

@Twodio Twodio closed this as completed Jul 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants