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

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

Open Steve973 opened this issue 3 years ago • 7 comments

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.

Steve973 avatar Nov 15 '22 17:11 Steve973

Hello, @christophstrobl I understand that you are very busy, so I hope that tagging you is OK. Is my issue report ok, and is it something that you and your team will consider? I have cloned this repo, and, since I am not familiar with this code base, it would help if someone could point me in the right direction with regard to the packages/classes to look at for repository method invocation. And, please let me know if I can provide better details, or whatever you need.

Steve973 avatar Nov 19 '22 13:11 Steve973

The issue is scheduled for triage in the team. Please be patient and give us a little time. Thank you!

christophstrobl avatar Nov 21 '22 06:11 christophstrobl

Ok. Thank you for the update!

Steve973 avatar Nov 21 '22 17:11 Steve973

Good catch - thanks for reporting! We'll take care of this.

christophstrobl avatar Nov 28 '22 11:11 christophstrobl

Is there any way that there could be some resolution to this? It has been open for over a year now.

Steve973 avatar Dec 19 '23 20:12 Steve973