jasontaylordev / NorthwindTraders

Northwind Traders is a sample application built using ASP.NET Core and Entity Framework Core.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Discussion] Supporting database transaction

nagiramadan opened this issue · comments

Hello dears,
I want to know how we can support transaction on method level or per entity level and which layer should be.
for example if we have changes in different entity so i want to be sure all changes applied together.
(transaction on method level)
sometimes we want to ensure entity saved correctly without effecting other entities (transaction on entity level)

You may create a new scope and use that scopes DbContext? You need to inject IServiceProvider to create

You may create a new scope and use that scopes DbContext? You need to inject IServiceProvider to create

Thanks a lot for your help.
I know this way, but somehow i fell it isn't clean and easy way, i think may be there is something better.

If you're calling SaveChanges multiple times in your handlers then you can add a pipeline behavior that wraps the handler with a transaction, something like this:

    public class DbTransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
        where TRequest : IRequest<TResponse>
    {
        private readonly IDbConext _dbCtx;

        public DbTransactionBehavior(IDbConext dbCtx)
        {
            _dbCtx = dbCtx;
        }

        public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
        {
            TResponse response;

            using (var transaction = _dbCtx.BeginTransaction())
            {
                try
                {
                    response = await next();

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    // when disposed if either commands fails
                    transaction.Commit();
                }
                catch (DbUpdateConcurrencyException)
                catch (DbUpdateException)
                {
                    // TODO: Throw transaction error
                }
            }

            return response; // Continue
        }
    }

I usually handle transient database errors in another handler. This pipeline will wrap all handlers, even those that might not be making Db updates so I suggest you update accordingly
e.g. add an interface to target only handlers that require Db changes.

@GFoley83 Thanks a lot for your reply.
Actually using pipeline is really amazing. i'm trying to find something clean like that but i got stuck.
Also i found in some applications, they using attribute to achieve transaction over the method.

I Actually didn't catch what that mean. so can you please give me more details?

I usually handle transient database errors in another handler. This pipeline will wrap all handlers, even those that might not be making Db updates so I suggest you update accordingly
e.g. add an interface to target only handlers that require Db changes.

My pipeline above is only for Db transactions. In the past, I've used another pipeline for retrying Db deadlocks:
https://gist.github.com/GFoley83/3e0c6e3a5ca36204937aaa62f13e7a0f

Thank you for your interest in this project. This repository has been archived and is no longer actively maintained or supported. We appreciate your understanding. Feel free to explore the codebase and adapt it to your own needs if it serves as a useful reference. If you have any further questions or concerns, please refer to the README for more information.