Unit of Work Implementation

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
28,050
Reaction score
17,804
I've come across dozens of articles where this pattern is implemented in various different ways.

A reply by the user Lars-Evik has it as such

C#:
public class EFUnitOfWork : IUnitOfWork
{
    private readonly DbContext context;

    public EFUnitOfWork(DbContext context)
    {
        this.context = context;
    }

    internal DbSet<T> GetDbSet<T>()
        where T : class
    {
        return context.Set<T>();
    }

    public void Commit()
    {
        context.SaveChanges();
    }

    public void Dispose()
    {
        context.Dispose();
    }
}

I found this example on a blog

C#:
public class UnitOfWork : IUnitOfWork
{
    protected string ConnectionString;
    private MovieContext context;

    public UnitOfWork(string connectionString)
    {
        this.ConnectionString = connectionString;
    }

    public MovieContext DbContext
    {
        get
        {
            if (context == null)
            {
                context = new MovieContext(ConnectionString);
            }
            return context;
        }
    }

    public int Save()
    {
        return context.SaveChanges();
    }

    public void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (context != null)
            {
                context.Dispose();
                context = null;
            }
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

And finally this example by Microsoft's Tom Dykstra. The newing up of the GenericRepository did raise an eyebrow.

C#:
    public class UnitOfWork : IDisposable
    {
        private SchoolContext context = new SchoolContext();
        private GenericRepository<Department> departmentRepository;
        private GenericRepository<Course> courseRepository;

        public GenericRepository<Department> DepartmentRepository
        {
            get
            {

                if (this.departmentRepository == null)
                {
                    this.departmentRepository = new GenericRepository<Department>(context);
                }
                return departmentRepository;
            }
        }

        public GenericRepository<Course> CourseRepository
        {
            get
            {

                if (this.courseRepository == null)
                {
                    this.courseRepository = new GenericRepository<Course>(context);
                }
                return courseRepository;
            }
        }

        public void Save()
        {
            context.SaveChanges();
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

Please could you guys advise on what is the correct way to do this. What do you do?
 
Full of boilerplate, signifying nothing. What problem are you trying to resolve?
 
Full of boilerplate, signifying nothing. What problem are you trying to resolve?

Hi roi. Basically this.

Yeah, DI is a beauty until this inevitably happens...

Code:
class FIXAdapter(ILog log, IUserRepo userRepo, IPortfolioRepo portfolioRepo, IInstrumentRepo repo, IQuantsAgent quantsAgent, IMetrics metrics, INotificationService notificationService, IHoldingsPublisher holdingsPublisher)
{
...
}
 
I have a diff implementation of UoW. Firstly, I use my own ORM that dynamically generates SQL based on the Type of the entity to be inserted/updated, etc. But you could use dapper too. I have a IUoW that provides for diff implementations.

My UoW has 3 lists: List<Object>. One for new entities, one for updated ones and then one for entities to be deleted. At the start of my request handling , I create a UoW instance and then pass it along to all the domain objects playing a part in the request handling. So basically the domain objects add new/updated entitities to the UoW rather than having to know about IRepos. E.g.
C#:
class  DomainObject
{
    void DomainObject(IUoW uow,...)
    {
      this.uoW = uow;   
    }
    void DoSomething(long id)
    {
        SomeEntity entity = uow.DataContext.Get<SomeEntity>(id);
        entity.SomeFunc();
        uow.AddUpdated(entity);
        
        SomeTrackingEntity trackingEntity = trackingCreationService.Create(...);
        trackingEntity.parentId = id;
        uow.AddNew(trackingEntity);
    }
}

class SomeService
{
    void SomeServiceFunc(long id)
    {
        using (IUow uow = CreateUow())
        {
            DomainObject domainObj = new DomainObj(uow);
            domainObj.DoSomething(id)

            uow.Execute();
        }
    }
}
Then once all is done, The UoW get executed in one DB transaction. The UoW execution essentially just runs through the lists and dynamically inserts/updates/deletes as required based on object type. Obviously there are some serious complexities with having to cache entites and make sure the entities you work with are not stale ones from the db.

It is nice and clean and does not suffer from overinjection. Also the domain objects are oblivious to where the data i saved to. They only see the UoW.
 
Thanks @Spacerat that makes things a lot clearer and a really clean way of doing things. Roi is right in that I was over doing it a little with DI.
 
i have used the repo and UoW pattern often, but I just experimented on a medium size project using EF Core forgoing repositories and UoW in favor of just using DbContext and it was pleasant.

I am never going to swop out my ORM for something else, so that wasn’t, and normally isn’t, a legitimate concern.
I have been doing a lot of GraphQL lately, so I just decided to use that mindset. DbContext is the “graphql query api”. The services are the consumer of that “API”, and they query their data how they want/need it.
 
i have used the repo and UoW pattern often, but I just experimented on a medium size project using EF Core forgoing repositories and UoW in favor of just using DbContext and it was pleasant.

I am never going to swop out my ORM for something else, so that wasn’t, and normally isn’t, a legitimate concern.
I have been doing a lot of GraphQL lately, so I just decided to use that mindset. DbContext is the “graphql query api”. The services are the consumer of that “API”, and they query their data how they want/need it.

I've been experimenting with that too, just using DBContext straight off the bat and it works well, fine!

Honestly I am quite liking EF, although at the moment I'm not using it in a purely code first manner with migrations etc but just hooking up a context to my current DB's.

I'll check GraphQL out and see what's the do with that.
 
Hi, I searched for Dapper related threads and came across this as the latest thread mentioning this ORM...

I've got a small question then I'll be on my way again.

Can someone please tell me why this very simple query does not see the parameters that I am passing in?

C#:
var results =
    con.Query<QueryEmployee>("SELECT EMP.SOL_ID, EMP.EMP_ID, EMP.EMP_NAME, EMP.EMP_INTLS, EMP.EMP_EMAIL_ID, EMP.IS_HEAD_TELLER, Role.USER_ID, EMP.DEL_FLG " +
                              "FROM tbaadm.get EMP, tbaadm.upr ROLE " +
                              "WHERE EMP.EMP_ID = ROLE.USER_EMP_ID AND ROLE.USER_WORK_CLASS = 200 AND ROLE.ROLE_ID LIKE 'BRM' AND EMP.EMP_ID = @EMP_ID", new { EMP_ID = "31294" }).SingleOrDefault();
 
Taking a stab in the dark, is EMP.EMP_ID a string column like the parameter you're passing?
 
Taking a stab in the dark, is EMP.EMP_ID a string column like the parameter you're passing?

Yes,
I tried many different ways, and the single quote in the query.


This dude was stuck, Marc Gavell in the last post works for Dapper I think.
 
Eish, 7 years ago...

Have you tried positional parameters with '?' instead of '@'?
 
Like '%BRM%'?

Whether I add a wildcard or not, it doesn't matter.
The query still comes back with as the query and the parameter as @EMP_ID, in other words, it does not populate it with the value I pass into it.
 
Ok I got it to work. Instead of using '@', one should use ':'.... MotherF###

I think it comes down to the difference between Oracle and SQL.
SQL probably uses '@' where Oracle uses ':'.
 
Top
Sign up to the MyBroadband newsletter
X