10

I'm implementing a DAL using entity framework. On our application, we have three layers (DAL, business layer and presentation). This is a web app. When we began implementing the DAL, our team thought that DAL should have classes whose methods receive a ObjectContext given by services on the business layer and operate over it. The rationale behind this decision is that different ObjectContexts see diferent DB states, so some operations can be rejected due to problems with foreign keys match and other inconsistencies.

We noticed that generating and propagating an object context from the services layer generates high coupling between layers. Therefore we decided to use DTOs mapped by Automapper (not unmanaged entities or self-tracking entities arguing high coupling, exposing entities to upper layers and low efficiency) and UnitOfWork. So, here are my questions:

  1. Is this the correct approach to design a web application's DAL? Why?
  2. If you answered "yes" to 1., how is this to be reconciled the concept of DTO with the UnitOfWork patterns?
  3. If you answered "no" to 1., which could be a correct approach to design a DAL for a Web application?

Please, if possible give bibliography supporting your answer.

About the current design:

The application has been planned to be developed on three layers: Presentation, business and DAL. Business layer has both facades and services

There is an interface called ITransaction (with only two methods to dispose and save changes) only visible at services. To manage a transaction, there is a class Transaction extending a ObjectContext and ITransaction. We've designed this having in mind that at business layer we do not want other ObjectContext methods to be accessible.

On the DAL, we created an abstract repository using two generic types (one for the entity and the other for its associated DTO). This repository has CRUD methods implemented in a generic way and two generic methods to map the DTOs and entities of the generic repository with AutoMapper. The abstract repository constructor takes an ITransaction as argument and it expects the ITransaction to be an ObjectContext in order to assign it to its proctected ObjectContext property.

The concrete repositories should only receive and return .net types and DTOs.

We now are facing this problem: the generic method to create does not generate a temporal or a persistent id for the attached entities (until we use SaveChanges(), therefore breaking the transactionality we want); this implies that service methods cannot use it to associate DTOs in the BL)

JPCF
  • 2,232
  • 5
  • 28
  • 50

4 Answers4

6

There are a number of things going on here...The assumption I'll make is that you're using a 3-Tier architecture. That said, I'm unclear on a few design decisions you've made and what the motivations were behind making them. In general, I would say that your ObjectContext should not be passed around in your classes. There should be some sort of manager or repository class which handles the connection management. This solves your DB state management issue. I find that a Repository pattern works really well here. From there, you should be able to implement the unit of work pattern fairly easily since your connection management will be handled in one place. Given what I know about your architecture, I would say that you should be using a POCO strategy. Using POCOs does not tightly couple you to any ORM provider. The advantage is that your POCOs will be able to interact with your ObjectContext (probably via Repository of some sort) and this will give you visibility into change tracking. Again, from there you will be able to implement the Unit of Work (transaction) pattern to give you full control over how your business transaction should behave. I find this is an incredibly useful article for explaining how all this fits together. The code is buggy but accurately illustrates best practices for the type of architecture you're describing: Repository, Specification and Unit of Work Implementation

The short version of my answer to question number 1 is "no". The above link provides what I believe to be a better approach for you.

Jason
  • 291
  • 1
  • 3
4

I always believed that code can explain things better than worlds for programmers. And this is especially true for this topic. Thats why I suggest you to look at the great sample application in witch all consepts you expecting are implemented.

alt text

Project is called Sharp Architecture, it is centered around MVC and NHibernate, but you can use the same approaches just replacing NHibernate parts with EF ones when you need them. The purpose of this project is to provide an application template with all community best practices for building web applications.

It covers all common and most of the uncommon topics when using ORM's, managing transactions, managing dependencies with IoC containers, use of DTOs, etc.

And here is a sample application.

I insist on reading and trying this, it will be a real trasure for you like it was for me.

Restuta
  • 5,855
  • 33
  • 44
2

You should take a look what dependency injection and inversion of control in general means. That would provide ability to control life cycle of ObjectContext "from outside". You could ensure that only 1 instance of object context is used for every http request. To avoid managing dependencies manually, I would recommend using StructureMap as a container.

Another useful (but quite tricky and hard to do it right) technique is abstraction of persistence. Instead of using ObjectContext directly, You would use so called Repository which is responsible to provide collection like API for Your data store. This provides useful seam which You can use to switch underlying data storing mechanism or to mock out persistence completely for tests.

As Jason suggested already - You should also use POCO`s (plain old clr objects). Despite that there would still be implicit coupling with entity framework You should be aware of, it's much better than using generated classes.

Things You might not find elsewhere fast enough:

  1. Try to avoid usage of unit of work. Your model should define transactional boundaries.
  2. Try to avoid usage of generic repositories (do note point about IQueryable too).
  3. It's not mandatory to spam Your code with repository pattern name.

Also, You might enjoy reading about domain driven design. It helps to deal with complex business logic and gives great guidelines to makes code less procedural, more object oriented.

Community
  • 1
  • 1
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
  • Do you have example of DDD with EF - I'm especially interested how do you define transactional boundaries. – Ladislav Mrnka Jan 07 '11 at 16:44
  • @Ladislav unfortunately, I'm not too familiar with EF. kind a blindly believing that NHibernate is still superior. but that would change only repository part. transactional boundaries are drawn by aggregate roots themselves because they are responsible for valid state and are persisted in atomic operation. correct modeling of them are the key. – Arnis Lapsa Jan 07 '11 at 21:48
  • Yes NHibernate is better. I would like to see some real world example of DDD + EF. I will probably create a question about this topic. – Ladislav Mrnka Jan 07 '11 at 23:47
1

I'll focus on your current issues: To be honest, I don't think you should be passing around your ObjectContext. I think that is going to lead to problems. I'm assuming that a controller or a business service will be passing the ObjectContext/ITransaction to the Repository. How will you ensure that your ObjectContext is disposed of properly down stream? What happens when you use nested transactions? What manages the rollbacks, for transactions down stream?

I think your best bet lies in putting some more definition around how you expect to manage transactions in your architecture. Using TransactionScope in your controller/service is a good start since the ObjectContext respects it. Of course you may need to take into account that controllers/services may make calls to other controllers/services which have transactions in them. In order to allow for scenarios where you want full control over your business transactions and the subsequent database calls, you'll need to create some sort of TransactionManager class which enlists, and generally manages transactions up and down your stack. I've found that NCommon does an extraordinary job at both abstracting and managing transactions. Take a look at UnitOfWorkScope and TransactionManager classes in there. Although I disagree with NCommon's approach of forcing the Repository to rely on the UnitOfWork, that could easily be refactored out if you wanted.

As far as your persistantID issue goes, check this out

Community
  • 1
  • 1
Jason
  • 291
  • 1
  • 3
  • Before all, thanks! you seem to be very interested. We create a Transaction at services but we use ITransaction; this interface exposes only two methods: Dispose and SaveChances. A Transaction object is a ObjectContext but it is treated as that on DAL; services only see ITransaction. Saving and Disposing a Transaction is programmers responsibility at service methods. We do not implement nested transactions and they are simple, so we do not consider rollbacks. – JPCF Jan 05 '11 at 21:26