Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Dennis 75 posts 397 karma points MVP
    Nov 02, 2021 @ 08:42
    Dennis
    0

    Database scoping and transactions in Dependency Injection

    Hi everyone, I have a question about using the database in Umbraco 8.

    I want to use a transaction on my database so that I can do a roll back on all my modifications, in case something goes wrong. I've seen examples for using the database with the IScopeProvider and with the IUmbracoDatabaseFactory. These examples are straight forward, but are not enough for my usecase. I want to hide my dependency on the database behind a repository class / interface and I want my services to depend on the interface. Say I have ServiceA and ServiceB, each relying on RepositoryA and RepositoryB respectively:

    public class MyClass
    {
        private readonly ServiceA _serviceA;
        private readonly ServiceB _serviceB;
    
        // using dependency injection to inject my services
        public MyClass(ServiceA serviceA, ServiceB serviceB)
        {
                _serviceA = serviceA;
                _serviceB = serviceB;
        }
    
        // notice how the communication with the database is not visible in this use case.
        // I want that, so that I can easily replace my implementation without having to replace all database references throughout the code.
        public void MoveById(int id)
        {
            var thing = _serviceA.GetAndDelete(id);
            _serviceB.Insert(thing);
        }
    
        // An alternative approach that would be acceptable for me as well:
        public void AlternativeMoveById(int id)
        {
            // Can I make some context provider that can create my services for me so that they use the same database perhaps?
            using(var scope = _someContextProvider.CreateSomeContextObject())
            {
                try
                {
                    var serviceA = scope.GetServiceA();
                    var serviceB = scope.GetServiceB();
                    var thing = serviceA.GetAndDelete(id);
                    serviceB.Insert(thing);
                    scope.Commit();
                }
                catch(Exception e)
                {
                    scope.Rollback();
                }
            }
        }
    }
    

    If ServiceB throws an exception, the action from ServiceA should be rolled back. However, should I use IScopeProvider or IUmbracoDatabaseFactory, then each service has their own scope and I cannot share a transaction.

    Scope provider also doesn't have a service provider / factory, so I don't think I can pull up the IScopeProvider to MyClass.

    The question: How can I make sure in this use case that ServiceA and ServiceB share the same database connection object and transaction?

Please Sign in or register to post replies

Write your reply to:

Draft