morphia icon indicating copy to clipboard operation
morphia copied to clipboard

MappedClass collection value could come from a field

Open jmkgreen opened this issue 12 years ago • 9 comments

From Ronald Feicht on the users mailing list:

One feature we like about mongoDB is separating each customer's data into his own collection: db.[customerId].orders for customerId 57 would result in collection name 'db.57.orders', for customerId 133 'db.133.orders' etc. To our disappointment morphia may not be used for this because the value of the annotation @Entity("...") in paranthesis must be a constant. What if you could reference an attribute of the class to be used to comprise the collection's name like so: @Entity(customerId) public class Orders { private Integer customerId;

public Orders(customerId) { this.customerId = customerId; }

public Orders() { this(0) } ... }

jmkgreen avatar May 24 '13 08:05 jmkgreen

The parameters of an annotation need to be a compile time constants... would adding a parameter to @Entity to specify which field name to use as the collection work? Seems like it could be error prone

reynoldsm88 avatar May 24 '13 17:05 reynoldsm88

Indeed, that thought occurred to me too. I was thinking along the lines of:

@Entity(collectionFromField="accountId")

But as you say, it becomes a runtime error and therefore less attractive.

An alternative:

@Entity class Account { @CollectionNameFromValue private int accountId }

This isn't perfect either. But better. If no sensible value can be located then fall back to standard behaviour.

Better ideas welcomed.

Sent from my iPad

On 24 May 2013, at 18:44, Michael Reynolds [email protected] wrote:

The parameters of an annotation need to be a compile time constants... would adding a parameter to @Entity to specify which field name to use as the collection work? Seems like it could be error prone

— Reply to this email directly or view it on GitHub.

jmkgreen avatar May 24 '13 20:05 jmkgreen

I'm a user but I'm new to the source, I'd have to dive in... is there a way we could have that @CollectionNameFromValue annotation override the values in @Entity and possibly log a warning explaining the default behavior...

reynoldsm88 avatar May 24 '13 20:05 reynoldsm88

I don't want to log a warning for what could be intentional behaviour - experience tells us crying wolf is bad.

I do want to document the behaviour in the javadoc properly. It is possible to debug what happened by accessing the resulting MappedClass so enhancing that would be good.

Sent from my iPad

On 24 May 2013, at 21:43, Michael Reynolds [email protected] wrote:

I'm a user but I'm new to the source, I'd have to dive in... is there a way we could have that @CollectionNameFromValue annotation override the values in @Entity and possibly log a warning explaining the default behavior...

— Reply to this email directly or view it on GitHub.

jmkgreen avatar May 25 '13 07:05 jmkgreen

I'd like to have a stab at this, might post back here for some clarifying questions... I have a fork so I'll do an update and play around with it

reynoldsm88 avatar May 28 '13 22:05 reynoldsm88

You will need to adjust MappedClass.getCollectionName().

What I would do:

  1. Add a CollectionNameFromValue annotation and add it to the list of interesting annotations inside MappedField
  2. Add a MappedField.hasCollectionName boolean method test
  3. Add a MappedClass.hasCollectionNameFromField boolean method test that proxies into each of the mappedFields hasCollectionName
  4. Alter MappedClass.getCollectionName() to inspect for hasCollectionNameFromField and return this string ahead of reverting to original behaviour.

As an additional matter there are validation rules and you should add one preventing:

a) CollectionNameFromValue annotation at the class level b) More than one CollectionNameFromValue annotation being found.

It is also possible you will encounter the ReflectionUtils class. This traverses the class and it's inheritance tree to discover items such as annotations.It's useful to understand the order it works in.

Please do not forget the unit tests :)

On 28 May 2013 23:23, Michael Reynolds [email protected] wrote:

I'd like to have a stab at this, might post back here for some clarifying questions... I have a fork so I'll do an update and play around with it

— Reply to this email directly or view it on GitHubhttps://github.com/jmkgreen/morphia/issues/68#issuecomment-18584322 .

jmkgreen avatar May 29 '13 08:05 jmkgreen

Thanks, I'll look into it later tonight or tomorrow.

reynoldsm88 avatar May 29 '13 18:05 reynoldsm88

Fields seem like the wrong way to do this. Shouldn't the collection name be associated via the Datastore or better yet via the BasicDAO? Seems like you should have a DAO per collection in general. Right now you are assumed to but the collection name is taken from the @Entity annotation or the Class name.

If it were optionally allowed to be in the constructor of the DAO or Datastore you could decouple the collection name from the class of object stored. This is how other DAO's or ODM's do it. That would allow runtime specification of the collection name and multiple collections per POJO Class. It would also not break any existing code that uses Morphia.

So the code would take the name from the DAO constructor, if specified, or the @Entity, if specified, or failing all else, the Class name.

pferrel avatar May 30 '13 20:05 pferrel

I've added some methods in trunk to allow runtime changing of the DBCollection in some areas. This provides a very quick and dirty "fix" but has minimal use-case coverage.

Your idea of an additional constructor sounds reasonable. However, a programmer would need to introduce code to instantiate lots of short-lived DAOs if he wanted a collection based on a runtime value such as that from a field.

Such changes can be made and released then revoked based on feedback - more likely if an implementation is a disaster to document and explain. Here's hoping what can be done doesn't cause more [support] questions than justifiable.

On 30 May 2013 21:47, Pat Ferrel [email protected] wrote:

Fields seem like the wrong way to do this. Shouldn't the collection name be associated via the Datastore or better yet via the BasicDAO? Seems like you should have a DAO per collection in general. Right now you are assumed to but the collection name is taken from the @Entityhttps://github.com/Entityannotation or the Class name.

If it were optionally allowed to be in the constructor of the DAO or Datastore you could decouple the collection name from the class of object stored. This is how other DAO's or ODM's do it. That would allow runtime specification of the collection name and multiple collections per POJO Class. It would also not break any existing code that uses Morphia.

So the code would take the name from the DAO constructor, if specified, or the @Entity https://github.com/Entity, if specified, or failing all else, the Class name.

— Reply to this email directly or view it on GitHubhttps://github.com/jmkgreen/morphia/issues/68#issuecomment-18707246 .

jmkgreen avatar May 30 '13 21:05 jmkgreen