0

I am in the process of making project decisions on development patterns for a solution, which involves the use of Entity Framework 6 as the ORM choice, and ASP.NET MVC 5.

I need insight on how transactions and business logic will be implemented. In respect to layers, I came to an initial assumption for the design where Entity Framework on top of SQL Server can be considered the Data Access Layer (DAL). On top of Entity Framework, there will be a Service Layer, where business logic and validation will be implemented. On top of the Service Layer, I will have ASP.NET MVC Controllers consuming what the service layer offers.

Let me ellaborate on this initial conclusion drawn as a starting point for defining the architecture:

I want to follow principles to achieve the minimum complexity scenario possible, in respect to layers, abstractions and all the solution components responsibilities. As an excercise, with this "simplicity" in mind, I could just embrace the template "proposed" by Microsoft as when you just create a new Visual Studio ASP.NET MVC Web application, but I believe that does not fit the minimum design scenario needed for an enterprise application, since in Microsoft's template, the controller directly makes use of Entity Framework DbContext and consumes the Data Access Layer, besides the fact that no service layer is present. This leads to several issues, such as extremely tight coupling between the presentation and data access layer, as well as the so called "fat controller" problem, where controllers become the bloated piece of the software with all the added responsibilities of business logic, transactions, and so on, making it truly a mess to software maintainability with, for example, the most basic principle of DRY (don't repeat yourself) being violated since you would get duplicated code and logic all over your fat controllers.

Ramping up the next stage on the path from simplicity to complexity, I assume it is fair to add a Service Layer to the design, because this way ASP.NET MVC controllers would talk only to this service layer, who would be responsible for all CRUD and validation of CRUD operations, and all other more complex business logic operations. This Service Layer then would talk to the data access layer being represented by Entity Framework.

I would stop there and say the design with these proposed layers is enough, but that's where I need more insight on how to proceed. I need to resolve the question on how would transactions be implemented, if you think of them as a wrapper for a series of individual operations performed by methods responsible for validation and business logic residing in classes inside the service layer. In terms of implementation using Entity Framework, if I get every individual operation performed by a service layer method to issue a .SaveChanges(), I would lose the ability of having DBContext to behave like a Unit of Work, wrapping up a single .SaveChanges() for many individual DBSet operations. In this case, the DBSets may behave like repositories. Many people argue that Entity Framework's DBContext and DBSet are implementations if Unit of Work and Repository pattern, respectively.

In a more objective question then, how can I implement these patterns using directly DBContext and DBSet, without any further abstraction into new generic or specific entity repository classes and unit of work generic class? The implementation needs to rely on the consumption of a service layer for the reasons I have already stated.

I think an answer to that would be just the last complexity leap I feel necessary to get my "least complex viable design".

Let me put a more concrete example to illustrate:

In my service layer, I have 2 methods to implement validation logic for 2 insert operations, with a programmer defined method Insert such as:

EntityOneService.Insert
EntityTwoService.Insert

Each of these methods in their corresponding service layer classes would have access to a DBContext and use DBSet.Add to signal they should be persisted, in case all validation and/or business logic passes. The desired scenario is that I can use each service layer method call in an isolated way, and/or in groups, such as in a new different service layer class method, such as:

OperationOnePlusTwoService.Insert

This new method would implement calls to EntityOneService.Insert and EntityTwoService.Insert, IN A TRANSACTION-LIKE FASHION.

By transaction-like I mean that all calls must succeed, not violating any validation or business rule, in order to have the persistence layer to commit the operations.

DBContext.SaveChanges() apparently would have to be called only once for this to happen, OUTSIDE of any service layer Insert method implementation. In the context of an ASP.NET Controller consuming service layer methods, how could that be achieved, without actual implementation of a Unit of Work and Repostory abstraction over DBContext and DBSet?

Any advice please would be very much appreciated. I am not posting this to argue the value of a real abstraction and implementation of Repository and Unit of Work patterns, or if Entity Framework's DBContext and DBSet are or are not equivalent to proper Repository and Unit of Work patterns, that's not the point. My project requirements do not involve in any way the need to decouple the application from Entity Framework, or to ideally and fully promote testability. These are not concerns and I am well aware of consequences and future maintainability impacts on not adopting full fledged implementations of half a dozen layers and all design patterns possible to make a big world-class enterprise solution.

1

1 Answer 1

1

desired scenario is that I can use each service layer method call in an isolated way ... but that behave IN A TRANSACTION-LIKE FASHION.

This is rather simple with EF, assuming your services are not remote (in which case transactions are not advisable in the first place).

In the simplest implementation, each service instance requires a DbContext to be passed in its constructor, and contributes its changes to that DbContext. The orchestrating controller code can control the lifetime of the DbContext and control its use of transactions.

In practice interfaces, rather than concrete service types are typically used, and Dependency Injection is often used instead of constructors. But the pattern is the same.

eg

using (var db = new MyDbContext())
using (var s1 = new SomeService(db))
using (var s2 = new SomeOtherService(db))
using (var tran = db.Database.BeginTransaction())
{
  s1.DoStuff();
  s2.DoStuff();
  tran.Commit();
}

David

Sign up to request clarification or add additional context in comments.

2 Comments

Hello, thanks a lot for the insight. When this snippet of code as you provided as an example is in an ASP.NET MVC controller action method, does it ensure that one DBContext instance is used per web request? Is this the case for the enclosing of code in chained using blocks? One DBContext per web request is really a best practice? I have seen information elsewhere stating that the instantiation and disposal of DBContext should be done in Application_BeginRequest() and Application_EndRequest(), is it necessary?
I came across a real good blog post that clarifies much of what I'm asking. Anyway, please feel free to add comments. Managing Entity Framework DbContext Lifetime in ASP.NET MVC

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.