From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-14 07:27:33
|
Hi Paul, Hibernate's associations are fundamentally uni-directional. The reason for this is that Java object references and the Java collections framework only permit navigation in one direction ie. dereferencing an object reference, or retrieving an object from a collection. There is no way for an object to determine if it belongs to a collection, or what other objects hold references to it. It is _possible_ to implement a bidirectional association in Java as a seperate class. At one (very early) stage there was even something exactly like this in Hibernate. I threw the concept away because it is just too alien to idiomatic Java. Now, it *would* be possible to do something like you suggest, and have two seperate associations, which happen to map to the same database column. The problem with that is that such a solution is very, very bugprone. If your Master throws away the Set it was holding details in, and creates a new Set, the details objects will still have references to the same Master. When we come to persist this broken structure, the results will be nondeterministic. Well, actually I lie. It *is* deterministic. The one-to-many association always wins over the many-to-one association in the current implementation. Those semantics are not guaranteed under a future, more efficient, implementation of collections. There is _no_ way to fix this without creating new API classes that intrude upon the business model. Or otherwise annoy you. For example, you wouldnt be able to pass collections seamlessly from one object to another and stuff like that.... If you really need a bi-directional association (if bi-directional associations were really that essential then OO languages would have them - and none do) then you can do any of the following 1. Detail has a many-to-one association to Master. Master can select its Details using a query ( perhaps lazily, perhaps from PersistentLifecycle.load() ) FROM detail IN CLASS pkg.Detail WHERE detail.master.id = ? and then put them in a transient collection. (My favored solution.) 2. Master has a one-to-many association to Detail. Detail can get its Master using a query (not efficient). 3. Master has a one-to-many association to Detail. Master can set transient backpointers on each Detail from PersistentLifecycle.load() All these solutions run the same risk of bugs as if they would be implemented in the persistence layer. The difference is: they would be application bugs - the persistence layer will still behave deterministically. I _guess_ we could fix the Schema generator to detect and remove duplicated column names and let you do what you want to do .... It won't *break* Hibernate, and it _does_ have quite str8forward semantics in this version (ie. the bit about the collection end wining.) But if we fix it I would much rather leave that feature undocumented. What do others think? Gavin |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-14 10:07:25
|
>Your statement about such a concept being alien to idiomatic Java to me >seems to be putting the horse before the cart. While true, I think that >it loses sight of what we're building - for me at least that's the >object model. Hmmmmmmm. Perhaps. I was very keen to stay with the current approach of just adding persistence to Java, not trying to add any extra semantics, not trying to build an application framework. If you manage to convince me that its possible to do bidirectional associations with no xtra API then I'm sold on it. >There are ways to do this, and all the commercial O/R tools that I've >used support this. Basically the association is "managed" from one end >when it comes to persisting the association - and it's straightforward >to tell when things are screwy. Interesting. The thing I've used that does bi-directional associations - namely Visual Age for Java's EJB associations - uses a generated class that ensures association integrity from _both_ ends. Its arguably not a good design and is not consistent with the approach in this project. (I think they have a more difficult problem though, because the ends of the association might be remote.) >I don't see the problem. Your code (i.e. not Hibernate, the users code) >is still responsible for making sure all the persistent objects point >to the right places. This is true without persistence, and I wouldn't >expect the persistence layer to do this for you - that would be intrusive. (snip) >Yep - and that's fine. And if you wanted to you *could* do a consistency >check quite transparently. There's actually huge advantages in being >able to do that. Yeah, I was thinking about this on the way home, after firing off that last email and thinking "Well, you could just let the users manage integrity themselves, but validate the state before we persist anything" ... All we would need to implement this approach is some code to validate the association somewhere. There wouldn't need to be any other changes to the runtime engine and there wouldn't need to be any API. This would make me happy. I've been thinking of one-to-many associations while I've been writing this, but I think much the same thing goes for many-to-manys (where its a collection on each end - mapped to the one table). |
From: Paul S. <pau...@ne...> - 2002-02-14 11:10:52
|
Okay, I think we're (almost?) on the same page. I'm *not* advocating a heavy framework that does a whole bunch of magic for you, like maintaining integrity of bidirectional associations. Where a bidirectional association exists simply tweak the relational mapping. For example to avoid "doubling up" on foreign keys to provide visibility from both ends as is done now in a one-to-many. This gives the possibility of integrity checking, which in my experience is very useful once the database gets large and/or complex. No extra API should be needed - it's still non-intrusive. Hibernate shouldn't manage the integrity of the association - the programmer still has to ensure both ends match. The code should be no different if the class is being persisted or not, at least in this respect. PaulS. Gavin_King/Cirrus%CI...@ci... wrote: >>Your statement about such a concept being alien to idiomatic Java to me >>seems to be putting the horse before the cart. While true, I think that >>it loses sight of what we're building - for me at least that's the >>object model. >> > > Hmmmmmmm. Perhaps. I was very keen to stay with the current approach of > just adding persistence to Java, not trying to add any extra semantics, not > trying to build an application framework. If you manage to convince me that > its possible to do bidirectional associations with no xtra API then I'm > sold on it. > > >>There are ways to do this, and all the commercial O/R tools that I've >>used support this. Basically the association is "managed" from one end >>when it comes to persisting the association - and it's straightforward >>to tell when things are screwy. >> > > Interesting. The thing I've used that does bi-directional associations - > namely Visual Age for Java's EJB associations - uses a generated class that > ensures association integrity from _both_ ends. Its arguably not a good > design and is not consistent with the approach in this project. (I think > they have a more difficult problem though, because the ends of the > association might be remote.) > > >>I don't see the problem. Your code (i.e. not Hibernate, the users code) >>is still responsible for making sure all the persistent objects point >>to the right places. This is true without persistence, and I wouldn't >>expect the persistence layer to do this for you - that would be intrusive. >> > (snip) > >>Yep - and that's fine. And if you wanted to you *could* do a consistency >>check quite transparently. There's actually huge advantages in being >>able to do that. >> > > Yeah, I was thinking about this on the way home, after firing off that last > email and thinking "Well, you could just let the users manage integrity > themselves, but validate the state before we persist anything" ... All we > would need to implement this approach is some code to validate the > association somewhere. There wouldn't need to be any other changes to the > runtime engine and there wouldn't need to be any API. This would make me > happy. > > I've been thinking of one-to-many associations while I've been writing > this, but I think much the same thing goes for many-to-manys (where its a > collection on each end - mapped to the one table). |
From: Paul S. <pau...@ne...> - 2002-02-14 09:04:07
|
Hi Gavin, some comments below, but I think the main issues here are (1) the value of associations over just collections, and (2) how you might implement this either in a product or as a work-around. Below are my observations and *opinion*, I'd welcome other input on this. IMO associations are key - the fact that you happen to implement them using collections in Java is a mere detail. We work on an object model, then translate that into code. The kinds of things you mention might be possible, but I cannot see *why* you would want to do them. Your statement about such a concept being alien to idiomatic Java to me seems to be putting the horse before the cart. While true, I think that it loses sight of what we're building - for me at least that's the object model. Anyway, more comments below. PaulS :) Gavin_King/Cirrus%CI...@ci... wrote: > Hi Paul, > > Hibernate's associations are fundamentally uni-directional. The reason for > this is that Java object references and the Java collections framework only > permit navigation in one direction ie. dereferencing an object reference, > or retrieving an object from a collection. There is no way for an object to > determine if it belongs to a collection, or what other objects hold > references to it. It is _possible_ to implement a bidirectional association > in Java as a seperate class. At one (very early) stage there was even > something exactly like this in Hibernate. I threw the concept away because > it is just too alien to idiomatic Java. > > Now, it *would* be possible to do something like you suggest, and have two > seperate associations, which happen to map to the same database column. The > problem with that is that such a solution is very, very bugprone. If your > Master throws away the Set it was holding details in, and creates a new > Set, the details objects will still have references to the same Master. > When we come to persist this broken structure, the results will be > nondeterministic. There are ways to do this, and all the commercial O/R tools that I've used support this. Basically the association is "managed" from one end when it comes to persisting the association - and it's straightforward to tell when things are screwy. > Well, actually I lie. It *is* deterministic. The one-to-many association > always wins over the many-to-one association in the current implementation. > Those semantics are not guaranteed under a future, more efficient, > implementation of collections. > > There is _no_ way to fix this without creating new API classes that intrude > upon the business model. Or otherwise annoy you. For example, you wouldnt I don't see why this would be the case. Could you elaborate? > be able to pass collections seamlessly from one object to another and stuff > like that.... I don't see the problem. Your code (i.e. not Hibernate, the users code) is still responsible for making sure all the persistent objects point to the right places. This is true without persistence, and I wouldn't expect the persistence layer to do this for you - that would be intrusive. > If you really need a bi-directional association (if bi-directional > associations were really that essential then OO languages would have them - I won't touch that one. > and none do) then you can do any of the following > > 1. Detail has a many-to-one association to Master. Master can select its > Details using a query ( perhaps lazily, perhaps from > PersistentLifecycle.load() ) > > FROM detail IN CLASS pkg.Detail WHERE detail.master.id = ? Isn't this what happens anyway? > and then put them in a transient collection. (My favored solution.) > > 2. Master has a one-to-many association to Detail. Detail can get its > Master using a query (not efficient). > 3. Master has a one-to-many association to Detail. Master can set transient > backpointers on each Detail from PersistentLifecycle.load() > > All these solutions run the same risk of bugs as if they would be > implemented in the persistence layer. The difference is: they would be > application bugs - the persistence layer will still behave > deterministically. Yep - and that's fine. And if you wanted to you *could* do a consistency check quite transparently. There's actually huge advantages in being able to do that. > > I _guess_ we could fix the Schema generator to detect and remove duplicated > column names and let you do what you want to do .... It won't *break* > Hibernate, and it _does_ have quite str8forward semantics in this version > (ie. the bit about the collection end wining.) But if we fix it I would > much rather leave that feature undocumented. What do others think? |