morphia
morphia copied to clipboard
Dynamic collection NamingStrategy
Is your feature request related to a problem? Please describe. We use different collections based on the tenant. Previously (v1.x) it was possible to override the getCollectionName method in the Mapper. We would like to be able to use a dynamic NamingStrategy based on the current tenant. However, the current NamingStrategy sets the collectionName in the EntityModel on load and it cannot be changed after that.
Describe the solution you'd like The NamingStrategy should be called when the getCollectionName() method is called on the EntityModel. Or at least, there should be an option to make it dynamic, so that it's called on getCollectionName().
Describe alternatives you've considered Can't see any alternative options at the moment.
You can define your own NamingStrategy
and configure Morphia to use that instead. Simply pass the class name for your custom strategy rather than the named type.
We have implemented the NamingStrategy
but it's applied when the EntityModel
is first mapped and cannot be changed after that.
In our case, we have multiple collections for the same object, one for each tenant. Which collection the object is written to depends on which tenant is currently saving the object. For example, we have tenanta.objects
, tenantb.objects
, tenantc.objects
and so on.
The NamingStrategy
allows us to manipulate the objects
part of the collection name, but not to dynamically add the tenant
part.
Before we used to override the getCollectionName
method of the Mapper
which was called when the collection name was needed. However, with the NamingStrategy
that's no longer possible as it's set upfront.
Multitenancy isn't directly supported in 2.x though it's on the roadmap for 3.x. If you need something like that now, your best bet is to create a Datastore
per tenant which is less than ideal, I would agree, but as of now it's the only real option.
I've made the change locally to support this use case.
I've added a new method to the EntityModelBuilder
which exposes the NamingStrategy
. Then in the EntityModel
constructor I store a copy of the NamingStrategy
in the EntityModel
itself. That way the NamingStrategy
can be called directly when getCollectionName
is called.
@NonNull
public String getCollectionName() {
if (namingStrategy == null) {
throw new MappingException(Sofia.noMappedCollection(getType().getName()));
}
return namingStrategy.apply(type.getSimpleName());
}
As NamingStrategy
is called at runtime, we can use it to supply the tenant.
Not sure if this works as a broader solution, but thought it might be worth sharing. Of course, it could be optimised, maybe with an option specifying if the NamingStrategy
should be cached, in which it works as it did previously.