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.

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?

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? 

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]

Reply via email to