by Eabin 03 Dec 14:53
Update OneToMany relations

Hi rob,

Is there an easy way to update OneToMany relations automatically when new items are created and saved? The easiest thing I could come up with (besides reloading the full object, which is not always possible), is prone to errors because i always have to think about invalidating all references:

User user = getCurrentUser();
Subscription s = user.getSubscription(categoryId);
if ( s == null ) s = new Subscription(categoryId);
Ebean.save(s);
Subscription sDb = Ebean.find(Subscription.class, s.getId());
user.setSubscription(categoryId, sDb);

and in User.java I have the following:
@OneToMany
private Set Subscription subscriptions;

and setSubscription(...) replaces the Subscription in the Set with the given value.


would it be possible to have Ebean.create(Subscription.class) which invalidates all Set Subscription ? or is there at least a way to invalidate the Set? because IIRC Ebean.refresh(user) does not invalidate ManyToOne and OneToMany properties.

Thanks for your great work, keep it up!
Eabin

04 Dec 08:48
by Rob

OK, I may not be quite following you correctly but...

How about putting a Cascade.Persist on the relationship - that is on the OneToMany User.subscriptions.

When Ebean saves a user... it would cascade and save the subscriptions. Ebean would detect which subscriptions are 'dirty' and save those. When Ebean saves a subscription (by cascading) it makes sure the subscription has its parent User set [it sets the user to the subscription automatically].

... but you code does a bit more than that...
I'd have to guess at what your methods...
user.getSubscription(categoryId);
user.setSubscription(categoryId, sDb);
... do... possibly search the Set of subscriptions for the category.

I think... you should be able to create a new subscription, set its cetegory, add it to the user's set (of subscriptions), save the user (with the save cascade) ... ebean will detect that only the one subscription is 'dirty' and saves it (and in doing so also sets the user to the newly inserted subscription automatically).

If I'm off base... perhaps send me the code... rbygrave at yahoo dot code.

Cheers, Rob.

04 Dec 08:51
by Rob

Not too sure what 'Invalidate the set' means... but I have added a refreshMany(Object bean, String manyPropertyName) to the api for 0.9.4.

So...
Ebean.refreshMany(user, "subscriptions")

will refresh the set of subscriptions on a user. Not sure if that helps you though.

19 Dec 14:07
by Eabin

hm, cascading would be one option.

i just thought (for the sake of simplicity) it would be cool that whenever i do:

Ebean.save(someSubscription);

all Set Subscription in all classes become invalid, and will be re-fetched on the next call to getSubscription();

or do you think this would have a very bad performance penalty?

consider the following example (some pseudo code, no IDE at hand :) )
------------------------------------
class User {
@Id
Long id;
@OneToMany
Set Subscription subscriptions;
}

class Subscription {
@Id
Long id;
@ManyToOne
User user;
}

main:
User u = getCurrentUser();
Set Subscription s = u.getSubscriptions();
//s contains ids [1,2,3]
Subscription newS = new Subscription();
newS.setUser(u);
Ebean.save(newS);
s = u.getSubscriptions();
//ebean detects that subscriptions are out of date, and refetches them
//s now contains ids [1,2,3,newS.id]
-----------------------------

what do you think?

19 Dec 14:13
by Eabin

and while i'm at it: it would be nice to get a proxified object as return value to Ebean.save()

so i can do:
newUser = Ebean.save(newUser);

and then a newUser.getSubscriptions(); would actually work.

regards,
eabin

19 Dec 23:31
by Rob

Hmmm, I'm not sure I "get" it yet...

With the subscriptions... you could do...

Ebean.save(newS);
Ebean.refreshMany(user,"subscriptions");
s = newS.getSubscriptions();

But I don't understand what is wrong with...

Ebean.save(newS);
s = newS.getSubscriptions();

... in that s contains all the subscriptions. Yes 1,2,3 where fetched earlier and could be considered not 'read consistent' with respect to the new subscription. Is that the issue (or perhaps a DB Trigger?).

Now that said... there will be cases where DB Triggers mean that when someone saves a bean of a certain type they will always want that bean re-queried because a DB Trigger modified it and that modification is not reflected in the bean. So perhaps this is a similar situation?

19 Dec 23:38
by Rob

RE: the save returning a proxy...

newUser = Ebean.save(newUser);
Set<Subscription> s = newUser.getSubscriptions();

so s is null... and normally you would...
newUser.setSubscriptions(new LinkedHashSet());

... and returning a proxy means that you don't have to set a new LinkedHashSet().
Okay, Hmmm... I'll think about that.

Create a New Topic

Title:
Body:
 
Introduction User Guide (pdf) Install/Configure Public JavaDoc Whitepapers
General Database Specific Byte Code Deployment Annotations Features
Top Bugs Top Enhancements
woResponse