spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

Allow registering converters to use DTO's instead of Entities with a Repository

Open remonvv opened this issue 2 years ago • 0 comments

Problem Currently the typical pattern for MongoRepository<T, ID> based interfaces is something like

// Domain type + persistence schema spec
@Document(...)
class SomeEntity {
    @Id
    UUID id;
    ...
}

interface SomeRepository extends MongoRepository<SomeEntity, UUID> {
    ...
}

class SomeService {
    final SomeRepository repository;

    SomeEntity get(UUID id) {
        return repository.findById(id)
            .orElseThrow(...);
    }
}

The above reflects most setups in examples, tutorials and Spring Boot classes are structured but it leaks information about how an entity is stored in a persistence layer into the service layer which is questionable (I know, subjective). In other words, the above approach conflates the definition of domain types (models) with specifying how such a type should be persisted to a specific storage solution, especially since most of the annotations needed are spring-data-mongodb specific.

For developers that prefer to keep the two separated as follows ...

// Domain type
class SomeEntity {
    UUID id;
    ...
}

//  Persistence schema spec
@Document(...)
class SomeDocument {
    @Id
    String id;
    ...
}

// NOTE: Here we'd want the MongoRepository to use the model type as 'T' rather than the
// document type. Mongo config or some other mechanism should allow us to specify that for actual
// persistence `SomeDocument` should be used as the document schema definition and mapping target.
interface SomeRepository extends MongoRepository<SomeEntity, UUID> {
    ...
}
...

...there is currently no practical way to use Spring Converter<S, T> or more practical mapping solutions such as mapstruct to automatically map database document object to and from model types (or if there is, it's not obvious how to go about it since none of the callback interfaces such as BeforeConvertCallback and friends allow the work at the right time).

Proposal Add/allow a mechanism that lets developers configure a mapping/converting interface of some sort such that given M (model type), D (document type), ID (primary id type) a MongoRepository can be defined using <M, ID> whilst some mongo config element allows us to specify that D is the entity that needs to be used by the ORM process and allows specifying a mapper M<->D explicitly, e.g :

@Override
protected void configureConverters(MongoConverterConfigurationAdapter converterConfigurationAdapter) {
    ...
    converterConfigurationAdapter.registerDocumentConverterPair(modelToDocumentConverter, documentToModelConverter);
    ...
}

I'm sure there's a more elegant solution to it that avoids the somewhat unwieldy unidirectional Converter<S,T> route since you'd always need to support mapping in both directions but whatever the solution looks like I think there should be a way to do this.

If such a mechanism exists I'd much appreciate a pointer in that direction.

remonvv avatar Jul 13 '22 16:07 remonvv