Graphinder – Encapsulating persistence layer

Recently we’ve been talking a little about difference between domain and persistence models.
The main reason I mentioned for using both is making our domain logic completely persistence agnostic.
But how do we actually tell another developer using our persistence layer API to go with an exact behavior we want?
Since database context, persistence models and ways of mapping are generally visible outside of the data access layer, I began to search for a solution to get rid of it.
This article will elaborate in short on encapsulating persistence (or data access) layer, so that only the things we want to be used from other layers are the things that are exposed.

Encapsulating database context

Let’s think of a simple DbContext that EntityFramework offers:

Wherever our data access project is referenced, AlgorithmContext is accessible. That’s a huge NO-NO!

So how about we make our AlgorithmContext internal?

But what internal keyword actually means? Let’s see:

The internal keyword is an access modifier for types and type members. Internal types or members are accessible only within files in the same assembly.

As we’ve already made our data access layer a separate project, it’s a separate assembly. Therefore, our context won’t be visible for other projects referencing it.
So far we’re good. First goal achieved: encapsulating persistence layer.
But still, we need to expose it somehow, so layers referencing our data access layer can actually, you know… access data. :)

Exposing data access

As stated in previous article, I’ve moved from repository pattern to queries and commands approach.
Let’s make a quick recall on how an example of query would look like. I’ll use simple example based on actual Graphinder code, as opposed to examples used in previous article to get closer to real world case:

As AlgorithmContext is already internal I can’t expose it outside assembly with public keyword, because that would cause an accessibility mismatch. That’s actually great, because whenever I’ll attempt to use my context around data access project, there is no way I will raise its accessibility above internal.


Query accessibility:

Context accesibility:

“Cannot access internal field ‘Context’ here”

Exactly what we wanted here! Cool!

But we want our API to be idiot-proof, don’t we?
No playing around with persistence models here. No knowledge on how anything is mapped, on how everything is persisted. Right?
Just make it all internal then. If we’re encapsulating persistence layer properly, only knowledge of very few things is exposed:

  • How to Query data from database
  • How to send Commands so that data is either created/modified or processed

No other functionality should be exposed here.

Wanna play around with my approach? Go visit GitHub then:

Last word of reminder

Such design is not reflection-proof. There is no such code. It’s also not idiot-proof if your fellow guys from team change signature from internal to public because it’s “easier”. Messier is always easier.

Leave a Reply
