0

I have a few questions about the DAO design pattern.

Let's suppose that I'm building a simple 2-tier MVC web app with a presentation layer and a persistence layer that communicates with a relational database. From what I understand, DAOs are meant to obfuscate how entities are defined and stored from the presentation layer so that these details can be changed to use, say, an in-memory database later on. Furthermore, a DAO is generally defined for a single entity in the underlying data model. Notably, this way of using the DAO pattern is encouraged by the JPA framework. When used as intended, the annotations that JPA provides for entity classes closely mirror how those entities would be modeled in a relational database.

My questions are: How can the presentation layer invoke a DAO without revealing how entities in the persistence layer are defined? Does the use of a DAO imply a service that sits above it in the persistence layer and handles requests from the presentation layer? If we ignore this issue and use the entities in the presentation layer anyway, how can they be augmented or adjusted for evolving requirements in the presentation layer without affecting code in the persistence layer?

2 Answers 2

1

I would suggest that a lot of your questions and the surrounding context would be answered in more detail by looking up guidelines on the specific architecture you're working with.

For the purpose of this question, I'm only going to address your concrete questions, and avoid doing the entire architecture spiel.

If we ignore this issue and use the entities in the presentation layer anyway, how can they be augmented or adjusted for evolving requirements in the presentation layer without affecting code in the persistence layer?

I assume that by "entity", you are referring to a class that is an identical representation of your persistence format (e.g. table structure).

On that assumption the direct answer is that you can't. You won't have encapsulated your entities within your persistence layer, since the entities are being exposed publicly, to be used and referenced by the consumers of the persistence layer.

Is that a problem? Well, personally I don't like it. I would always introduce a mapping conversion between the internal entity and the exposed data model.

How can the presentation layer invoke a DAO without revealing how entities in the persistence layer are defined?

For n-tier architecture, the general solution is that each layer should provide a mapping abstraction on its internal components so as not to expose them to the outside world. Even if the internal component is identical to its mapped counterpart, I would advise you already create this layer so as to avoid tight coupling and a potentially difficult refactor if these two models ever do diverge.

However, I also tend to work with more domain-oriented architectures that rely on inverted dependencies, where the persistence layers' public interface is not defined by the persistence layer itself. This makes it patently impossible for the interface to expose the entity, since the interface definition does not even have access to the entity's definition in the first place.
But that's more a matter of working with a different architecture than the n-tier architecture you're working with right now, so that might not be a relevant answer here.

Does the use of a DAO imply a service that sits above it in the persistence layer and handles requests from the presentation layer?

Your answer is asking if that's a universal given. The answer to that is no. But is it generally a good idea? I would say yes in most scenarios, and as a default unless you have a good justification to not do so.

"Service" is a vague term. I assume you're referring to a repository here (or something that fills the same role). This repository can act as the mapping point, therefore its public interface can rely on using the mapped DTOs instead of the entities itself.

Effectively, you would see the entity models being used inside the repo method bodies, but the repo method signatures would be using the DTOs instead. Rouch example:

    public void Create(PersonDto personDto)
    {
        var personEntity = mapper.Map(personDto);

        // Create logic, using personEntity
    }

    public PersonDto GetById(Guid id)
    {        
        var personEntity = ...; // Fetch logic, using personEntity

        var personDto = mapper.Map(personEntity);

        return personDto;
    }

This is a really simple example, highlighting that the first (for input models) and last (for output models) lines of your method body would convert the data to/from the entity model, so that the rest of the method can be centered around the entity model without exposing that entity to the outside world.

6
  • I'm not fully convinced that mapping to a DTO is beneficial here. I've seen way too many projects that have empty DTO layers being mapped to other empty DTO layers for the sake of architecture and decoupling. I want to see behavior in a layer, or another really good reason for it's existence. Types used internally within the same system are safer to use in multiple layers provided the IDE's refactoring tools allow you to easily restructure and reorganize the code base. Commented Sep 26, 2024 at 4:20
  • That being said, if types are used across different systems such that refactoring tools in the IDE don't help, now the layer has a good reason to exist. The decoupling the DTO provides insulates other systems or components from changes that are not easily fixed. Commented Sep 26, 2024 at 4:25
  • @GregBurghardt: Define "layer". Architecturally, I would refer to "the persistence layer", which includes in it any persistence logic and related mapping. But I would refer to the concept of mapping in and of itself as a "layer of abstraction", which is not referring to an "architecture layer" in the same sense that "persistence layer" would be. So when you say "I want to see behavior in a layer", I agree with you if you're referring to an architectural layer, but not if you're referring to the other definition of "layer" that I mentioned. Commented Sep 26, 2024 at 4:58
  • 1
    @GregBurghardt: Maybe to put it differently I'm not advocating for an empty passthrough layer (i.e. a whole new service class) which does nothing but mapping. I'm advocating for the addition of a mapping to the existing layer (i.e. repository or similar service). Based on your feedback, I get the feeling that you may have interpreted this answer as suggesting the former. Commented Sep 26, 2024 at 5:01
  • Could I perhaps go a step further and propose that whatever structure sits atop a DAO (which we agree should exist in the vast majority of cases) must: 1. Implement an interface defined in the presentation layer, and 2. be introduced into the presentation layer via dependency injection? Commented Sep 26, 2024 at 10:51
0

From what I understand, DAOs are meant to obfuscate how entities are defined

Obfuscation in software development according to wikipedia...

...is the act of creating source or machine code that is difficult for humans or computers to understand.

DAO pattern is abstracting the database representation to decouple the application from the persistence environment.

How can the presentation layer invoke a DAO without revealing how entities in the persistence layer are defined?

To have communication between layers without revealing the entities from the persistence layer abstract the communication model, in this case the DTOs, and have the DAO methods get parameters and return values of abstract types defined by the communication model. The entities could implement the abstract types defined by the communication model without exposing the database representation when using an abstract model.

                    PresentationDaoDto           Entity
    Presentation <----------------------> DAO <----------> DB

...where PresentationDaoDto is an abstract type and if Entity is implementing the PresenattionDaoDto the DAO methods having in signature the return type PresentationDaoDto could return data of type Entity.

Summed up: an application using a persistence layer defines three models (1) entity model describing the database (2) an abstract model describing transfer data, that is describing the available getter methods (3) the implementation of the abstract model that could be same with or different model than the entity model. When the entity model is also implementing the transfer data abstract model along with the getters for the data from the database, that are unavailable beyond the DAO layer since the DAO layer communicates with the adjacent layer using the abstract data transfer model, implements also the getters described by the abstract data transfer model.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.