On 10/31/07, syg6 <[EMAIL PROTECTED]> wrote:
>
>
> Giddyap, adding the MERGE CascadeType did it.
>
> Note, in my previous post I left off the cascade and fetch attribs of the
> OneToMany by accident. This is what it should have looked like:
>
>
> @OneToMany(cascade = { CascadeType.ALL },fetch = FetchType.EAGER)
> @JoinColumn(name="objectA")
> @org.hibernate.annotations.Cascade({
> org.hibernate.annotations.CascadeType.DELETE_ORPHAN,
> org.hibernate.annotations.CascadeType.SAVE_UPDATE})
> public Set<AAndBJoin> getAAndBJoins ()
>
>
> Note that in the OneToMany I already had cascade = { CascadeType.ALL },
> which in theory should include the MERGE CascadeType. And this seemed to
> be
> working when updating an existing ObjectA with elements in the AAndBJoin
> Collection.
>
> But when creating a new ObjectA with elements in the AAndBJoin Collection
> it
> did not work. So, as per your advice, I added the Hibernate MERGE
> Annotation:
>
>
> @OneToMany(cascade = { CascadeType.ALL },fetch = FetchType.EAGER)
> @JoinColumn(name="objectA")
> @org.hibernate.annotations.Cascade({
> org.hibernate.annotations.CascadeType.DELETE_ORPHAN,
> org.hibernate.annotations.CascadeType.SAVE_UPDATE,
> org.hibernate.annotations.CascadeType.MERGE })
> public Set<AAndBJoin> getAAndBJoins ()
>
>
> And it works!


Glad it does! Looks like you've stumbled on a Hibernate bug here. As you
said, it should work with just the normal CascadeType.ALL....

As per your comment that for everything to work 100% 'AAndBJoin must own the
> relationship from AAndBJoin to ObjectB', I guess I should use the changes
> I
> made in ObjectA to make it the owner of the AAndBJoin relationship as an
> example.
>
> In order to make ObjectA the owner of the AAndBJoin relationship I did the
> following:
>
> 1. in ObjectA get rid of the 'mappedBy=objectA' attribute of the
> @OneToMany
> Annotation
> 2. in ObjectA add the @JoinColumn(name='idObjectA').
> 3. in AAndBJoin add 'insertable=false, updatable=false' to the
> @JoinColumn(name='idObjectA') Annotation.
>
> Well, AAndBJoin looks like this:
>
> @ManyToOne
> @JoinColumn(name="idObjectB")
> public ObjectB getObjectB()
>
> And ObjectB looks like this:
>
> @OneToMany(mappedBy="objectB")
> public Set<AAndBJoin> getAAndBJoins ()
>
> So I'm not sure quite what to do. The class I want to be the owner
> (AAndBJoin) doesn't have a 'mappedBy' attribute to get rid of because
> 'mappedBy' is only for OneToMany. And it already has a Join column, so I
> don't have to add one. And in ObjectB, I don't have a Join column to add
> the
> insertable and updateable attributes to ...


This is all as it should be. The default (read preferred) case is for the
ManyToOne side of the relationship to be the owner, which is what you've got
with your existing annotations for the AAndBJoin -> ObjectB relationship.

To tell you the truth I am hesitant (read: scared to death!) to change it
> now that it works. But if you could give me a hint as to how to change
> these
> mappings to make AAndBJoin the owner of the relationship with ObjectB,
> perhaps I'll give it a try.


No need!

Jeez, what a long, strange trip it's been. I feel as though I owe something
> to the AppFuse community for all the help I've received. Do you think it
> would be worthwhile to do a tutorial for AppFuse 2, something along the
> lines of the old Weblog tutorial, but using 'complex' objects like this
> one?
> In other words, a 'simulated' ManyToMany using OneToMany and a Model
> Object
> to represent the association? Something like:
>
> Weblog -> OneToMany -> WeblogPost
> Post -> OneToMany -> WeblogPost
> WeblogPost -> ManyToOne -> Weblog
> WeblogPost -> ManyToOne -> Post
>
> I know I sure could have used a tutorial, and I don't think my situation
> is
> anything out of the ordinary. Having attributes in a Join table must be
> pretty common. In my project alone I have 6!!
>
> If there is any interest I'll try to throw it together.


Always interested in improving documentation - all contributions most
welcome!

Thanks again listers, and specifically Mssr. Horowitz.


Pleasure. Glad its all working!

Mike

Bob
>
> , with a ManyToMany
>
>
> Mike Horwitz wrote:
> >
> > On 10/31/07, syg6 <[EMAIL PROTECTED]> wrote:
> >>
> >>
> >> Well, your advice sounds good but there's one thing I don't understand.
> >> You
> >> said that:
> >>
> >>
> >> When you perform an operation on the entity that owns
> >> the relationship the relationship will change. Perform an operation on
> >> the
> >> other side of the relationship and nothing will happen to the
> >> relationship
> >> itself
> >>
> >>
> >> All changes made to the Collection of ObjectBs associated with ObjectA
> >> are
> >> done from the ObjectA side of the relation, in objectaform.jsp. When I
> >> update an ObjectA, Hibernate is automatically updating changes in the
> >> Collection of ObjectBs -- inserts, updates, deletes (except when I
> delete
> >> ALL elements from the Collection, in which case I update the Collection
> >> manually, as discussed in previous messages). And when I create a new
> >> ObjectA, Hibernate is at least trying to save Collection elements
> >> properly.
> >> The only problem is that it can't properly save them because it doesn't
> >> yet
> >> have an idObjectA to correctly populate the idObjectA foreign key
> column
> >> in
> >> the aandbjoin table.
> >
> >
> > As previously explained there are exceptions where it appears to work as
> > you
> > have observed above. However if you want it all to work, and work
> > properly,
> > then you MUST make ObjectA the owner of the relationship. One other word
> > of
> > caution in your case: If you want it all to flow neatly from ObjectA
> down
> > to
> > ObjectB through the realtionship on AAndBJoin, then ObjectA must own the
> > relationship from ObjectA to AAndBJoin and AAndBJoin must own the
> > relationship from AAndBJoin to ObjectB. Also note that saving a new
> > ObjectB
> > with a new set of associations will not work.
> >
> > So it seems to me that Hibernate already at least thinks ObjectA is the
> >> owner, otherwise it wouldn't be making inserts, updates and deletes in
> >> the
> >> aandbjoin table, no?
> >
> >
> > No.
> >
> >
> >> At any rate, I tried changing the mapping as section '2.2.5.3.2.1.
> >> Bidirectional' recommends:
> >>
> >> ObjectA class:
> >>
> >> @OneToMany
> >> @JoinColumn(name="idObjectA")
> >> @org.hibernate.annotations.Cascade(
> >> { org.hibernate.annotations.CascadeType.DELETE_ORPHAN,
> >>    org.hibernate.annotations.CascadeType.SAVE_UPDATE
> >> })
> >> public Set<AAndBJoin> getAAndBJoins ()
> >>
> >> AAndBJoin class:
> >>
> >> @ManyToOne
> >> @JoinColumn(name="idObjectA", insertable=false, updatable=false)
> >> public ObjectA getObjectA()
> >>
> >> And now when I save a new ObjectA with associated ObjectBs I get a
> >> 'object
> >> references an unsaved transient instance - save the transient instance
> >> before flushing' error.
> >>
> >> Anything else I need to do?
> >
> >
> > Yes. The Hibernate operation called on a save in the AppFuse default DAO
> > is
> > merge(), so you need to make sure merge is cascaded.
> >
> > Mike
> >
> > Thanks!
> >> Bob
> >>
> >>
> >> Mike Horwitz wrote:
> >> >
> >> > On 10/31/07, syg6 <[EMAIL PROTECTED]> wrote:
> >> >
> >> >>
> >> >> I used both Hibernate docs and Hibernate in Action to come up with
> >> this
> >> >> mapping, it seems to be the 'standard' way to doing this (mapping a
> >> >> relation
> >> >> with attributes, in my case, quantity). The example you cited is a
> >> >> relation
> >> >> without attributes, so I don't think it's suitable for me. From
> >> Hibernate
> >> >> in
> >> >> Action:
> >> >>
> >> >> 'you should ask whether it might be better to map CategorizedItem
> >> >> [AAndBJoin] as an entity class and use two one-to-many
> associations.'
> >> >
> >> >
> >> > In full agreement! What you end up with is not a many-to-many
> >> > relationship,
> >> > but two one-to-many relationships with an additional entity (at least
> >> in
> >> > Hibernate land). The example relates to each of these one-to-many
> >> > relationships.
> >> >
> >> >
> >> >
> >> >> At any rate, I posted just before seeing your message. The problem
> >> with
> >> >> deleting all elements in the Collection (which was 99% of my last
> >> post!)
> >> >> is
> >> >> resolved.
> >> >>
> >> >> The only problem that remains is when I save a new ObjectA and at
> the
> >> >> same
> >> >> time associate ObjectBs, that I don't have an idObjectA to assign to
> >> the
> >> >> FK
> >> >> column of the aandbjoins table, so the AAndBJoin Objects are
> >> improperly
> >> >> saved (idObjectA is null), and are not loaded when I load the
> ObjectA
> >> >> (see
> >> >> my last message). Your suggestion didn't have anything to do with
> this
> >> >> problem did it?
> >> >
> >> >
> >> > It did. In Hibernate one side of the relationship is designated as
> the
> >> > owner
> >> > of the relationship. When you perform an operation on the entity that
> >> owns
> >> > the relationship the relationship will change. Perform an operation
> on
> >> the
> >> > other side of the relationship and nothing will happen to the
> >> relationship
> >> > itself. There may be some exceptions to this rule, but I have found
> >> that
> >> > if
> >> > I stick to it all works more or less as expected.
> >> >
> >> > In your terms it seems you want ObejctA to own the relationship (the
> >> > OneToMany side). Your annotations need to change to reflect this.
> >> >
> >> >
> >> >
> >> >> I have tried making the two foreign key columns in AAndBJoin
> >> >> nullable=false,
> >> >> like this:
> >> >
> >> >
> >> > This is not enough on its own to make the one to many the owner of
> the
> >> > relationship:
> >> >
> >> > "To map a bidirectional one to many, with the one-to-many side as the
> >> > owning
> >> > side, you have to remove the mappedBy element and set the many to one
> >> > @JoinColumn as insertable and updatable to false. This solution is
> >> > obviously
> >> > not optimized and will produce some additional UPDATE statements."
> >> >
> >> > Also note from the example that a JoinColumn annotation is required
> on
> >> > both
> >> > sides of the relationship.
> >> >
> >> > Mike.
> >> >
> >> >
> >> >> public class AAndBJoin
> >> >> {
> >> >> private Long id;
> >> >> private ObjectA objectA;
> >> >> private ObjectB objectB;
> >> >>
> >> >> @Column(name="idAAndBJoin")
> >> >> @Id @GeneratedValue(strategy = GenerationType.AUTO)
> >> >> public Long getId()
> >> >>
> >> >> @ManyToOne
> >> >> @JoinColumn(name="idObjectA",nullable=false)
> >> >> public ObjectA getObjectA()
> >> >>
> >> >> @ManyToOne
> >> >> @JoinColumn(name="idObjectB",nullable=false)
> >> >> public ObjectB getObjectB()
> >> >>
> >> >> but when I save a new ObjectA I get an 'not-null property references
> a
> >> >> null
> >> >> or transient value' error.
> >> >>
> >> >> As you can see I am using an id as the Primary Key. If I were to use
> a
> >> >> Composite Primary Key -- idObjectA and idObjectB -- would this
> 'force'
> >> >> Hibernate to fill-in values for these ids, even when saving a new
> >> >> ObjectA?
> >> >>
> >> >> Thanks!
> >> >> Bob
> >> >>
> >> >>
> >> >>
> >> >> Mike Horwitz wrote:
> >> >> >
> >> >> > I think your issue is that in your case you want the one-to-many
> >> side
> >> >> of
> >> >> > the
> >> >> > relationship to own the relationship. In order to make this happen
> >> you
> >> >> are
> >> >> > going to have to change your annotations. The following section of
> >> the
> >> >> > Hibernate manual should help: http://tinyurl.com/ypdln3 look for
> >> >> section
> >> >> > 2.2.5.3.2.1.
> >> >> >
> >> >> > Mike
> >> >> >
> >> >> > On 10/31/07, syg6 <[EMAIL PROTECTED]> wrote:
> >> >> >>
> >> >> >>
> >> >> >> Well what's curious is that with my other 'normal' ManyToMany
> (see
> >> my
> >> >> >> previous post. ObjectA has a Collection of ObjectC) if from my
> >> ObjectA
> >> >> >> form
> >> >> >> I delete all ObjectCs, the 'objectcs' Request parameter is 'null'
> >> and
> >> >> >> Hibernate correctly deletes all ObjectC objects.
> >> >> >>
> >> >> >> But with my ObjectB Collection, this does not work, I assume
> >> because
> >> I
> >> >> am
> >> >> >> doing a 'manual' ManyToMany, in other words ObjectA and ObjectB
> >> have
> >> a
> >> >> >> OneToMany relation with AAndBJoin, and AAndBJoin has a ManyToOne
> to
> >> >> both
> >> >> >> ObjectA and ObjectB. The behavior should be the same, no? If I
> send
> >> >> >> 'null',
> >> >> >> it should delete all elements from the Collection, just as it
> does
> >> >> with
> >> >> >> my
> >> >> >> ObjectC Collection. But it does not.
> >> >> >>
> >> >> >> At any rate, I've tried manually deleting all ObjectBs from the
> >> >> >> Collection;
> >> >> >> In my ObjectAFormController onSubmit() I tried the following
> (only
> >> >> when
> >> >> >> the
> >> >> >> 'objectbs' Request parameter is null):
> >> >> >>
> >> >> >> 1. Load ObjectA from database (to get existing ObjectB
> Collection).
> >> >> >> 2. Use ObjectBManager to get() each ObjectB
> >> >> >> 3. Use ObjectBManager to remove() each ObjectB
> >> >> >> 4. Call ObjectAManager.save()
> >> >> >>
> >> >> >> And I get a 'deleted object would be re-saved by cascade (remove
> >> >> deleted
> >> >> >> object from associations):' error, as I knew I would. And if I
> >> instead
> >> >> >> call
> >> >> >> objectA.setObjectBs(null) I get a 'A collection with
> >> >> >> cascade="all-delete-orphan" was no longer referenced by the
> owning
> >> >> entity
> >> >> >> instance' error.
> >> >> >>
> >> >> >> The only difference I can see between the Collection of ObjectBs
> >> and
> >> >> >> ObjectCs is that in my ObjectAFormController onSubmit(), after
> this
> >> >> line:
> >> >> >>
> >> >> >> ObjectA objectA = (ObjectA) command;
> >> >> >>
> >> >> >> ... if in the objectaform.jsp I have deleted all of the ObjectC
> >> >> elements
> >> >> >> from the Collection, objectA.getObjectCs() is null. Correct! And
> >> >> >> Hibernate
> >> >> >> goes on to delete these ObjectBs from the database. But if I have
> >> >> deleted
> >> >> >> all of the ObjectB elements from the Collection,
> >> objectA.getObjectBs
> >> ()
> >> >> is
> >> >> >> NOT null; it has the 'old' data, the Collection as it existed
> >> before
> >> >> >> doing
> >> >> >> the deletes. As such, Hibernate does not update the database. And
> I
> >> >> >> assume
> >> >> >> that's also why if I try to manually delete the elements, I am
> >> getting
> >> >> an
> >> >> >> error.
> >> >> >>
> >> >> >> Both Collections have a Custom PropertyEditor. The difference is
> >> that
> >> >> >> ObjectC only implements setAsText():
> >> >> >>
> >> >> >> public void setAsText(String id)
> >> >> >> {
> >> >> >> ObjectC objectC = objectCManager.get(new Long(id));
> >> >> >> setValue(objectC);
> >> >> >> }
> >> >> >>
> >> >> >> whereas the Custom PropertyEditor for ObjectB, because I use my
> own
> >> >> Model
> >> >> >> Object (AAndBJoin) to represent the Join, and has to grab a bunch
> >> of
> >> >> >> values
> >> >> >> from text and hidden fields in the form to create AAndBJoin
> >> Objects,
> >> >> >> implements setValue():
> >> >> >>
> >> >> >> public void setValue(Object object)
> >> >> >> {
> >> >> >> // array of values sent from text/hidden inputs in form
> >> >> >> String[] strings = (String[])object;
> >> >> >>
> >> >> >> Set<AAndBJoin> aAndBJoins = new LinkedHashSet<AAndBJoin>();
> >> >> >>
> >> >> >> for (number of text/hidden inputs in the page)
> >> >> >> {
> >> >> >>    AAndBJoin aAndBJoin = new AAndBJoin();
> >> >> >>    aAndBJoin.setId(new Long(strings[0]));
> >> >> >>    aAndBJoin.setObjectA(objectAManager.get(new
> Long(strings[1])));
> >> >> >>    aAndBJoin.setObjectB(objectBManager.get(new
> Long(strings[2])));
> >> >> >>    aAndBJoin.setQuantity(new Integer(strings[3]));
> >> >> >>    aAndBJoins.add(aAndBJoin);
> >> >> >> }
> >> >> >> super.setValue(aAndBJoins);
> >> >> >> }
> >> >> >>
> >> >> >> Anyway, the point is if I delete all ObjectC elements, ObjectC's
> >> >> Custom
> >> >> >> PropertyEditor is not being called (because since it's null
> there's
> >> no
> >> >> >> reason to call it) and when I call objectA.getObjectCs() I get
> >> null,
> >> >> ok.
> >> >> >> But
> >> >> >> when I delete all ObjectB elements, even though its Custom
> >> >> PropertyEditor
> >> >> >> isn't called either, when I call objectA.getObjectBs() I get the
> >> old
> >> >> >> Collection info, before the delete. Which is why Hibernate
> doesn't
> >> >> update
> >> >> >> the database, and why I get errors if I try to delete them
> >> manually.
> >> >> >>
> >> >> >> Odd, inconsistent behavior, no? It seems that since I am using my
> >> own
> >> >> >> Model
> >> >> >> Object (AAndBJoin) to represent the relation, I need to do
> >> something
> >> >> else
> >> >> >> to
> >> >> >> make Hibernate aware that all elements have been deleted. But I
> >> have
> >> >> no
> >> >> >> idea
> >> >> >> what!
> >> >> >>
> >> >> >> Incidentally, any ideas about the other problem? Where when I
> >> create
> >> a
> >> >> >> new
> >> >> >> ObjectA and associate various ObjectB elements, those AAndBJoin
> >> >> Objects
> >> >> >> are
> >> >> >> saved incorrectly, with idObjectA=null, because when I call
> >> >> >> objectA.save()
> >> >> >> I
> >> >> >> still don't have an idObjectA?
> >> >> >>
> >> >> >> Thanks, sorry for the long post,
> >> >> >> Bob
> >> >> >>
> >> >> >>
> >> >> >> DNewfield wrote:
> >> >> >> >
> >> >> >> > syg6 wrote:
> >> >> >> >> Something else I have noticed: deleting members of the
> AAndBJoin
> >> >> >> >> Collection
> >> >> >> >> seems to be working, more or less, now that I put the
> >> DELETE_ORPHAN
> >> >> >> >> Hibernate Annotation. But there is one case where it does NOT
> >> work
> >> >> --
> >> >> >> >> when
> >> >> >> >> you delete all of the elements. When you delete all of the
> >> >> elements,
> >> >> >> the
> >> >> >> >> 'AAndBJoin' Request parameter is of course null. What
> Hibernate
> >> >> should
> >> >> >> do
> >> >> >> >> in
> >> >> >> >> this case is delete all elements. But what it in fact does, is
> >> >> >> nothing.
> >> >> >> >>
> >> >> >> >> It seems that in order for Hibernate to properly delete
> elements
> >> >> from
> >> >> >> a
> >> >> >> >> Collection, at least one element has to be sent in the
> Request.
> >> >> Thus,
> >> >> >> if
> >> >> >> >> you
> >> >> >> >> had 4 and deleted 3, 1 element is sent in the Request and
> >> Hibernate
> >> >> >> >> compares
> >> >> >> >> the Collection before and after, and properly deletes 3. But
> if
> >> you
> >> >> >> >> delete
> >> >> >> >> all 4, in the Request 'null' is received, Hibernate seems to
> do
> >> no
> >> >> >> >> comparison, and deletes nothing. Ugh.
> >> >> >> >
> >> >> >> > You need to detect this case, because assigning "null" to the
> the
> >> >> >> > collection attribute is wrong--the appropriate answer is to
> >> retrieve
> >> >> >> the
> >> >> >> > (hibernate managed) collection, and either remove each item
> from
> >> it
> >> >> or
> >> >> >> > clear() the collection, then re-setting the (same) cleared
> >> >> collection
> >> >> >> to
> >> >> >> > the attribute.
> >> >> >> >
> >> >> >> > -Dale
> >> >> >> >
> >> >> >> >
> >> >>
> ---------------------------------------------------------------------
> >> >> >> > To unsubscribe, e-mail: [EMAIL PROTECTED]
> >> >> >> > For additional commands, e-mail:
> [EMAIL PROTECTED]
> >> >> >> >
> >> >> >> >
> >> >> >> >
> >> >> >>
> >> >> >> --
> >> >> >> View this message in context:
> >> >> >>
> >> >>
> >>
> http://www.nabble.com/Many-to-many-collection-problem-tf4670322s2369.html#a13507645
> >> >> >> Sent from the AppFuse - User mailing list archive at Nabble.com.
> >> >> >>
> >> >> >>
> >> ---------------------------------------------------------------------
> >> >> >> To unsubscribe, e-mail: [EMAIL PROTECTED]
> >> >> >> For additional commands, e-mail: [EMAIL PROTECTED]
> >> >> >>
> >> >> >>
> >> >> >
> >> >> >
> >> >>
> >> >> --
> >> >> View this message in context:
> >> >>
> >>
> http://www.nabble.com/Many-to-many-collection-problem-tf4670322s2369.html#a13508465
> >> >> Sent from the AppFuse - User mailing list archive at Nabble.com.
> >> >>
> >> >>
> ---------------------------------------------------------------------
> >> >> To unsubscribe, e-mail: [EMAIL PROTECTED]
> >> >> For additional commands, e-mail: [EMAIL PROTECTED]
> >> >>
> >> >>
> >> >
> >> >
> >>
> >> --
> >> View this message in context:
> >>
> http://www.nabble.com/Many-to-many-collection-problem-tf4670322s2369.html#a13511405
> >> Sent from the AppFuse - User mailing list archive at Nabble.com.
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: [EMAIL PROTECTED]
> >> For additional commands, e-mail: [EMAIL PROTECTED]
> >>
> >>
> >
> >
>
> --
> View this message in context:
> http://www.nabble.com/Many-to-many-collection-problem-tf4670322s2369.html#a13513652
> Sent from the AppFuse - User mailing list archive at Nabble.com.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>

Reply via email to