This is almost getting me crazy. EF bring us a very convenience experience in development.
However, if we need to use the Entity model in the upper layer, we always put a reference from the upper layer to DAL or some layer at the lower which is holding the Entity class. I have visualize the situation.
+-------------------+
| |
| Presentation |
(This layer is directly referring to DAL, which break the 3-tier architecture rules)
+-------------------+
|
|
|
|
+---------v---------+
| |
| BLL |
(Function that returning Entity Model)
+-------------------+
|
|
|
|
+---------v---------+
| |
| DAL |
(Repo & Entity Model)
+-------------------+
Implement something like DTO at BLL is quite heavy and cannot solve this issue completely. So I may not try to implement DTO at such layer.
In the meantime, I found that some project may take out those Entity Model
like the following diagram. Is it a good way to solve the problem?
+-------------------+
| |
+------------------+ Presentation |
| | |
| +---------+---------+
| |
| |
| |
| |
+-----v------+ +---------v---------+
| | | |
| Entities <-----------+ BLL |
| | (Function that returning Entity Model)
+-----^------+ +---------+---------+
| |
| |
| |
| |
| +---------v---------+
| | |
+------------------+ DAL |
| (Repositories) |
+-------------------+
Although this design can solve some of the problem, developers can attempt to update the entity to DB from Presentation Layer
by calling entity.SaveChanges()
. Which is so dangerous. How can I prevent other developer from calling SaveChanges()
at the upper layer?
Best Answer
The only sane way to do that is to enforce a true separation between layers, and the only reasonable way you can do that is to maintain your own set of Data Transfer Objects (DTO's) at the Presentation/BLL interface, which defeats the purpose of using Entity Framework.
Let me show you something.
At my previous job, we used Entity Framework, but we never called
SaveChanges()
or used theDBContext
object for anything except referring to the Entity classes. Instead, we used bare queries.Over time, we began to forego the use of generated DTO's from EF, and just began creating our own DTO's. Bare queries do not require all the machinery that EF puts into a DTO, like change tracking, and you can customize each DTO for specific queries.
This sounds like we were taking on a lot of work that Entity Framework already does for you, but it comes with some significant benefits:
In my current job, I carried over this technique, but replaced Entity Framework with Dapper, the micro-ORM that Stack Exchange uses. The queries look almost exactly like the one above. I use this tool to generate entity classes.
The nice thing about Dapper is it contains CRUD extensions that include change tracking. You just call
Update()
on the affected entities. The difference is that now you can hide the Update method from your Presentation layer if you want to; just forego theIDbConnection
object that Dapper uses.