Peuge
Peuge

Reputation: 1501

Calling SaveChanges after SaveChanges fails

I have the following test code:

try
{
    Product product = productService.GetProductById(1502);
    product.ProductName = "TEST PRODUCT NAME";

    throw new ArgumentException("");

    //Do some other DB updates

    //Call SaveChanges
    productService.SaveChanges();
}   
catch(Exception ex)
{
    logService.InsertLog(LogTypeEnum.Error, "test", ex);
    logService.SaveChanges();
}

The problem is that my services share a context per request (using StructureMaps HttpContextScoped). So when the failure occurs and I call logService.SaveChanges it saves the products new name. However I lose atomicity because the "other DB updates" will not be saved to the DB. What would be the correct way to implement this?

Upvotes: 1

Views: 120

Answers (1)

Richard
Richard

Reputation: 30628

This is always going to be a problem with context per-request. In a large project I started out with context per-request too, but have gradually removed it due to problems like this.

I would suggest identifying the scenarios like this where you are likely to need to write to your DB without calling SaveChanges - if it's all limited to this log service then perhaps you should re-implement this without the dependence on the context? Alternatively you should be able to specify a custom way of creating the log service with its own context (i.e. not just having one injected by the constructor).

I'm not familiar with the Structuremap syntax so here's something from Autofac which would do the same...

builder.RegisterType<MyContext>().InstancePerRequest();  // As you have already
builder
    .Register(c => new LogService(new MyContext())
    .As<ILogService>().InstancePerRequest();

This would construct LogService using an explicitly created context rather than the per-request instance which would've been injected had I registered it normally.

Upvotes: 1

Related Questions