Skip to content

Different methods of obtaining collection name between interface repositories and custom repositories may produce inconsistent results #4231

Open
@Steve973

Description

@Steve973

It appears that the collection name is obtained differently in different circumstances:

  1. When using an interface repository, with the usual methods, or added methods, spring-data-mongodb obtains the collection name from the model class -- either the lower-camel-case name of the class, or whatever is provided in the @Document annotation
  2. When using a custom implementation, the collection name is obtained from the MongoEntityInformation instance.

In most cases, this effectively results in the same value being obtained. However, this is not always the case. Consider the following situation:

  1. You have a repository interface called ItemRepository that extends MongoRepository and ItemRepositoryCustom (below)
  2. You have a custom repository interface called ItemRepositoryCustom
  3. You have an implementation for the ItemRepositoryCustom interface that also extends SimpleMongoRepository
  4. You configure a repository like this:
MongoDatabaseFactory mongoDatabaseFactory = new SimpleMongoClientDatabaseFactory(mongoClient, dbName);
MongoTemplate mongoTemplate = new MongoTemplate(mongoDatabaseFactory);
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate.getConverter().getMappingContext();
MongoPersistentEntity<Item> persistentEntity = (MongoPersistentEntity<Item>) mappingContext.getRequiredPersistentEntity(Item.class);
MappingMongoEntityInformation<Item, String> mongoEntityInformation = new MappingMongoEntityInformation<>(persistentEntity, collectionName);
ItemRepositoryCustomImpl customImpl = new ItemRepositoryCustomImpl(mongoEntityInformation, mongoTemplate);
ItemRepository repository = new MongoRepositoryFactory(mongoTemplate).getRepository(ItemRepository.class, customImpl);

Spring data will get the name from the model class when you use the interface methods, and it will use the value supplied in the MongoEntityInformation class when you use methods from SimpleMongoRepository. So, for the same repository, depending on which methods you use, you could operate on two different collection names when working with different methods from the same repository.

The expected behavior would be to get the collection name from the same place, no matter which method is being invoked, particularly when the collection name is customized, as it is in the code snipped above.

I have updated my example project to demonstrate this inconsistent behavior:

https://github.com/Steve973/multiple-mongo-config

When you run the tests, the relevant lines are:

15:48:05.699 [main] DEBUG org.springframework.data.mongodb.core.MongoTemplate - find using query: {} fields: Document{{}} for class: class com.example.multiplemongoconnections.model.Item in collection: coll1
... lines omitted ...
15:48:05.755 [main] DEBUG org.springframework.data.mongodb.core.MongoTemplate - find using query: { "name" : "test item"} fields: Document{{}} for class: class com.example.multiplemongoconnections.model.Item in collection: item

The configured collection name is coll1, and the model class is Item. When using a SimpleMongoDatabase method, it uses the configured value. When using a MongoDatabase interface extension with a @Query method, it uses the model class name.

I have not (yet) looked at the code, but, as I understand it, the interface methods are intercepted and queries are made based on the names of the methods, or the content of the query/aggregation in the annotation. In this proxy/aspect, can the instance be examined to determine if there is a custom implementation? If so, then obtain the collection name from the implementation's MongoEntityInformation property. Else, obtain it from the model class. If whomever triages this ticket agrees that this behavior should be corrected, I can have a look at the code and submit a merge request with these changes. Just let me know.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions