Missing the unit of work

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
11 years ago
Not sure about you guys, but I really think a unit of work is needed. Right now every single update is a hit to the database resulting in many transactions.

I would suggest wrapping the IDbContext with an IUnitOfWork so you can submit whenever you want. Right now, every single order insert is like 20 hits to the database. Which in my opinion is too many.

The perfomance benefit of this approach is quite vast and is easy to test.
11 years ago
Yes, unit of work is needed. But it's more about business transactions. Right now we insert/update each entity immediately after an appropriate insert/update service method is called (for example, "ProductService.InsertProduct" or "ProductService.UpdateProduct"). With unit work we'll do the same number of database calls, but they'll be done at the end of request (once some kind of "Context.Commit" is called).

But I believe that unit of work does not manage how many database calls you'll have. Entity Framework is quite smart to do not make a database call if an entity (or any of its properties) wasn't changed.

P.S. Anyway I've just created a work item and investigate it a bit later.
11 years ago
a.m. wrote:
Yes, unit of work is needed. But it's more about business transactions. Right now we insert/update each entity immediately after an appropriate insert/update service method is called (for example, "ProductService.InsertProduct" or "ProductService.UpdateProduct"). With unit work we'll do the same number of database calls, but they'll be done at the end of request (once some kind of "Context.Commit" is called).

But I believe that unit of work does not manage how many database calls you'll have. Entity Framework is quite smart to do not make a database call if an entity (or any of its properties) wasn't changed.

P.S. Anyway I've just created a work item and investigate it a bit later.

The use case I had was the below:
            foreach (var product in products)
            {
                if (!product.ProductTagExists(tag.Id))
                {
                    product.ProductTags.Add(tag);
                    _productService.UpdateProduct(product);
                }
            }

Using a unit of work approach, all updates would be sent in one transaction which is many times faster. I have changed to unit of work aproach before and it is a lot faster. The commands are sent at the same time
11 years ago
[email protected] wrote:
Using a unit of work approach, all updates would be sent in one transaction...

No. I've just checked it in SQL Server Profiler (modified your example to invoke ProductService.UpdateProduct method only once). Separate SQL command was sent to SQL Server for each new product tag. For example, if you add two new products tags (tag1 and tag2), then they won't be added using one SQL command even if you use unit of work.

[email protected] wrote:
I have changed to unit of work aproach before and it is a lot faster. The commands are sent at the same time

Could you please share your changes? Maybe, I'm doing something wrong.
11 years ago
IDbContext is essentially a unit of work though isnt' it?

DbContext will keep track of any changes you make and can commit all at once. So, instead of calling this._context.SaveChanges(); in the EfRepository implementation, can't you just pass an IDbContext reference to your services?

public void SomeServiceMethod()
{
     _someRepositoryAccess.DoSomething();

     _anotherRepository.SomethingElse();
     _context.SaveChanges();
}

So, your services are responsible for flushing the changes, rather than in the repository class.
11 years ago
a.m. wrote:
Using a unit of work approach, all updates would be sent in one transaction...
No. I've just checked it in SQL Server Profiler (modified your example to invoke ProductService.UpdateProduct method only once). Separate SQL command was sent to SQL Server for each new product tag. For example, if you add two new products tags (tag1 and tag2), then they won't be added using one SQL command even if you use unit of work.

I have changed to unit of work aproach before and it is a lot faster. The commands are sent at the same time
Could you please share your changes? Maybe, I'm doing something wrong.


I did not make this test in nopCommerce nor EF, so not sure how  EF handles it. Can you do some stopwatches and see what is fastest?
11 years ago
dylanmorley wrote:
IDbContext is essentially a unit of work though isnt' it?

DbContext will keep track of any changes you make and can commit all at once. So, instead of calling this._context.SaveChanges(); in the EfRepository implementation, can't you just pass an IDbContext reference to your services?

public void SomeServiceMethod()
{
     _someRepositoryAccess.DoSomething();

     _anotherRepository.SomethingElse();
     _context.SaveChanges();
}

So, your services are responsible for flushing the changes, rather than in the repository class.

Well yeah, that is my suggestion
11 years ago
[email protected] wrote:
Well yeah, that is my suggestion


Ah sorry - from your first post I thought you wanted a new interface IUnitOfWork.
11 years ago
[email protected] wrote:
Can you do some stopwatches and see what is fastest?

I haven't done any stopwatches. But the number of executed SQL commands is the same. I presume it won't give us any real performance improvement. As I've written above the unit of work pattern is more often used for business transactions.
11 years ago
a.m. wrote:
Can you do some stopwatches and see what is fastest?
I haven't done any stopwatches. But the number of executed SQL commands is the same. I presume it won't give us any real performance improvement. As I've written above the unit of work pattern is more often used for business transactions.


Internally, SaveChanges will start and commit a transaction in SQL Server - you can see this happening in SQL Profiler.

Every time a repository method is called (Insert \ Update \ Delete) it will call save changes and go through the transaction process.

Instead of this, if IDbContext were called from the end of a service or controller method once all entity changes have been made, all SQL statements should be wrapped in a single transaction.

Yes, you will have the same amount of SQL statements, but this should still have performance benefits

Some people have implemented similar functionality along the lines of 'unit of work per http request', the uow starts on 'BeginRequest' and is comitted on 'EndRequest'. Personally, I think this is too late in the pipeline to handle any commit errors & it should be your controllers \ services that handle the SaveChanges.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.