Per your comment above, I think you could use some general architectural advice. Here's the approach that I used, which worked for me. I'm gonna call it "CQRS-lite" in that it doesn't use event sourcing or strictly separate data sources, but it'll solve the SRP issue you're wrestling with.
Here's how we would do reading:
public class FooController {
private IFooService _readService;
public ActionResult List();
}
// runs DB queries, maps them to viewmodels
// If you're using EF, use one DB context per HTTP request
// and turn off change tracking
public interface IFooService {
FooList List();
}
// a viewmodel, only used by this controller
// (and often only by one action/view)
public class FooList {
public IEnumerable<FooListItem> Foos;
}
And here's how we would do writing (this is the same MVC controller - I just broke the code up between reading and writing to make it easier to read):
public class FooController {
private IBus _bus;
[HttpPost]
public void Create(FooCreate model) { // could also return, e.g. RedirectToAction
_bus.Send(new CreateFoo {
Id = model.Id,
// map the other properties
})
}
}
// e.g. NServiceBus in memory, or you can write your own
// it just finds the handler for the command via your
// DI container
public interface IBus {
void Send(params ICommand[] commands)
}
// A command tells the system to do something.
// It's basically a serializable remote procedure
// call, can be sync or async
public class CreateFoo : ICommand {
public Guid Id;
// etc
}
// A command handler. DbContext should be scoped per-instance
// (not per HTTP request) or things get complicated.
// You can decorate Handle() with, e.g. _context.SaveChanges()
public class CreateFooHandler : IHandler<CreateFoo> {
private IDbContext _context;
public void Handle(CreateFoo message) {
// write stuff to the DB
}
}