db-jdo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jörg von Frantzius <joerg.von.frantz...@artnology.com>
Subject Re: Relationships mapped with mapped-by (long)
Date Wed, 06 Sep 2006 10:31:02 GMT
Hello Craig (et al.),

from what I understand of your proposals, you want to mandate *integrity 
of bidirectional associations*. Is that correct? That would be a great 
new feature!

Next to that, it seems to me that still you always want to silently 
remove objects from their relationships when those objects are deleted. 
In my opinion, this should only happen if we e.g. have 
delete-action="null" on the corresponding foreign key. As that can be 
declared only when foreign keys are declared for the association, maybe 
we should have something like "delete-action" on the field level, so the 
behaviour can easily be specified?

Apart from that, I'd have two questions. For "One-many relationships", 
you write:
> If the "one" side of instance A removes instance X (which currently 
> refers to A) from its collection, and instance X has not been added to 
> a different collection and its reference has not been changed to 
> another instance, the spec is silent. 
Why is the spec silent here?

My second question is: why do you want to prevent those "conflicting 
changes", or why do you see them conflicting at all? Why can't the 
second change simply override the first, in both cases?

Thanks for the proposals, regards,
Jörg

Craig L Russell schrieb:
> Javadogs,
>
> We have an issue with regard to the behavior of relationships mapped 
> using mapped-by, where there is a bidirectional relationship 
> instantiated by a single database artifact, either a foreign key or a 
> row in a join table.
>
> The spec currently defines a subset of behavior where relationships 
> are updated by the program, and the memory model must be updated to 
> reflect the change in the datastore after flush (including flush for 
> commit).
>
> The spec doesn't define the behavior when instances are deleted or 
> primary keys are updated. 
>
> There are interacting metadata tags that affect the way the database 
> schema is defined. Column attribute allows-null specifies whether the 
> column is nullable or not. Foreign-key attribute delete-action 
> specifies how the foreign key is defined in the database. Field 
> attribute mapped-by specifies the field on the other side that shares 
> a mapping artifact in the database. Field attribute null-value 
> specifies the behavior of null values at flush time. Field attribute 
> dependent specifies that there is a dependency relationship (if the 
> instance is deleted, the instance referred to by the dependent field 
> is also deleted).
>
> The proposals below do not add any more metadata concepts, but reuse 
> existing concepts. The proposals are intended for incorporation into 
> the JDO 2 maintenance release.
>
> Many-many relationships:
>
> These are implemented as join tables, in which each row in the join 
> table corresponds to an element (or key or value) in a field on each 
> of the two sides. The join table is typically mapped on one side, and 
> the field on the other side refers to the field with a mapped-by 
> attribute. But the behavior is the same regardless of which side 
> defines the mapping.
>
> If either side adds an instance to the map or collection, at flush 
> time a new row is added to the join table. The specification requires 
> that for consistency, the other side's collection be updated in memory.
>
> If either side removes an instance from the map or collection, at 
> flush time the corresponding row is removed from the join table. The 
> specification requires that for consistency, the other side's 
> collection be updated in memory to remove the corresponding element or 
> entry from the collection or map.
>
> If an instance participating in a relationship is deleted, and the 
> field referring to the other side is defined as dependent, then all 
> instances of the other side are deleted, and all rows in the join 
> table corresponding to the deleted instances are deleted.
>
> If an instance participating in a relationship is deleted, and the 
> field referring to the other side is not defined as dependent, at 
> flush time the corresponding rows are removed from the join table. I 
> believe that the specification requires that for consistency, all of 
> the other side's collections be updated in memory to remove the 
> corresponding element or entry from the collection or map. But I think 
> it would be a good idea to add this explicitly to the specification.
>
> One-many relationships:
>
> The foreign key is typically specified on the "many" side, which 
> declares a reference type; and the "one" side declares an element, 
> key, or value, and uses the mapped-by attribute. The specification 
> doesn't require the mapped-by attribute on the "one" side; it's just 
> less work to define it there.
>
> These relationships might also be mapped using a join table in which 
> the existence of a relationship is indicated by a row in the join 
> table. The semantics and behavior are the same as if the column 
> defining the relationship is in the "many" side's mapping.
>
> If the "many" side reference in instance X is updated (from instance A 
> to instance B) then the spec requires that the underlying database 
> column(s) be updated from referring to A to referring to B. The memory 
> model is made consistent, by removing X from A's collection and adding 
> X to B's collection. 
>
> If the "one" side of instance B adds instance X (which currently 
> refers to A) to its collection, at flush time the specification 
> requires that the underlying database column be updated in the row 
> corresponding to instance X to refer to B. The memory model is made 
> consistent, by removing X from A's collection and updating X to refer 
> to B. A conflicting update is one in which some other instance of the 
> "one" type also adds X to its collection, or instance X is changed so 
> it refers to an instance of the "one" type other than B.
>
> If the "one" side of instance A removes instance X (which currently 
> refers to A) from its collection, and instance X has not been added to 
> a different collection and its reference has not been changed to 
> another instance, the spec is silent. 
>
> <proposed>
> If the field in X is defined as null-value="exception", then at flush 
> time this is an error. If the column that defines the relationship is 
> defined as allows-null="false", then this is an error, as there is no 
> known value to which the column can be changed. If the column is 
> defined as allows-null="true" and the field in X is defined as 
> null-value="none", then the column is updated to null and the memory 
> model is changed so that the reference in X is null.
>
> Deleting an instance X on the "many" side results in removing the 
> instance from the database and updating the memory model to be 
> consistent. If the field of instance A that contains X is instantiated 
> in memory, then the collection is updated to remove X.
>
> Deleting an instance A on the "one" side that contains an instance X 
> is ok if instance X is also deleted in the same transaction. There are 
> two cases:
>
> o If the collection field is defined as dependent-element="true" then 
> instance X is also deleted by the jdo implementation. 
>
> o If instance X is not also deleted by the program, and the collection 
> field is defined with dependent-element="false" then instance X is not 
> deleted. If the field in X is defined as null-value="exception", then 
> at flush time this is an error, as the memory model cannot be made 
> consistent. If the column that defines the relationship is defined as 
> allows-null="false", then this is an error, as there is no known value 
> to which the column can be changed. If the column is defined 
> as allows-null="true", and the field in X is defined as 
> null-value="none", then at flush time the column is updated to null 
> and the memory model is changed so that the reference in X is null. 
> NOTE: This behavior can be done automatically by the database if the 
> foreign-key specifies delete-action="null".
> </proposed>
>
> One-one relationships:
>
> These relationships are symmetric from the object model perspective, 
> as currently the only metadata to describe whether one side or the 
> other can exist independently is the null-value attribute of field. 
> When mapped, typically the mapping is to a single unique foreign key 
> column. This column is defined on one side of the relationship, and 
> the mapping of the other side uses the mapped-by attribute. For the 
> purposes of this discussion, I'll refer to the side containing the 
> foreign key in its mapping as the mapped side, and the other as the 
> mapped-by side.
>
> If the mapped-by side reference of instance C is updated (from 
> instance Y to instance Z) then at flush time the underlying database 
> column(s) of Z is updated to refer to C. The specification requires 
> that the memory model be made consistent, by changing Z to refer to C. 
> Also, since there can only be one value in the database column 
> containing C, the row corresponding to Y must be changed, but if Y has 
> not also been updated to refer to another instance and no other 
> instance has been updated to refer to Y, there is no value to which to 
> set Y's reference except null.
>
> <proposed>
> If the field in Y is defined as null-value="exception", this is an 
> error. If the field is defined as null-value="none", and the column 
> defining the relationship is defined as allows-null="false", this is 
> an error. If the field is defined as null-value="none", and the column 
> defining the relationship is defined as allows-null="true", then the 
> column is updated to null and the memory model is made consistent by 
> setting the field in Y to null. 
> </proposed>
>
> If the mapped side of instance Y is set to instance D (and Y  
> currently refers to C), the spec requires that the underlying database 
> column be updated in instance Y to refer to D. The memory model is 
> made consistent, by setting the reference in D to Y and setting C's 
> reference to null. 
>
> <proposed>
> If the field in C is defined as null-value="exception", this is an 
> error. If the field is defined as null-value="none", the column in the 
> row corresponding to instance Y is updated to refer to D and there is 
> no longer any row with a reference to C. 
> </proposed>
>
> If the mapped-by side reference of instance C is deleted (and 
> currently instance C refers to Y and vice versa) and the field in C is 
> defined as dependent then at flush time both C and Y are deleted.
>
> If the field in C is not defined as dependent and Y has not been 
> changed to refer to another instance, then at flush time the reference 
> in Y to C must be set to null.
>
> <proposed>
> If the field in Y is defined as null-value="exception", this is an 
> error. If the field is defined as null-value="none", and the column 
> defining the relationship is defined as allows-null="false", this is 
> an error. If the field is defined as null-value="none", and the column 
> defining the relationship is defined as allows-null="true", then the 
> column in Y is updated to null and the memory model is made consistent 
> by setting the field in Y to null. 
> </proposed>
>
> If the mapped side reference of instance Y is deleted (and currently 
> instance Y refers to C and vice versa) and the field in Y that refers 
> to C is defined as dependent, then at flush time the rows 
> corresponding to Y and C are deleted.
>
> If the field is not defined as dependent, then at flush time the field 
> in C must be set to null.
>
> <proposed>
> If the field in C is defined as null-value="exception", this is an 
> error. If the field is defined as null-value="none", the row 
> corresponding to instance Y is deleted and there is no instance that 
> refers to C. 
> </proposed>
>
> <spec>
> The field on the other side of the relationship can be mapped by using 
> the mapped-by at- 
> tribute identifying the field on the side that defines the mapping. 
> Regardless of which side 
> changes the relationship, flush (whether done as part of commit or 
> explicitly by the user) 
> will modify the datastore to reflect the change and will update the 
> memory model for con- 
> sistency. There is no further behavior implied by having both sides of 
> the relationship map 
> to the same database column(s). In particular, making a change to one 
> side of the relation- 
> ship does not imply any runtime behavior by the JDO implementation to 
> change the other 
> side of the relationship in memory prior to flush, and there is no 
> requirement to load fields 
> affected by the change if they are not already loaded. This implies 
> that if the RetainVal- 
> ues flag or DetachAllOnCommit is set to true, and the relationship 
> field is loaded, then 
> the implementation will change the field on the other side so it is 
> visible after transaction 
> completion. 
> Conflicting changes to relationships cause a JDOUserException to be 
> thrown at flush 
> time. Conflicting changes include: 
> •adding a related instance with a single-valued mapped-by relationship 
> field to 
> more than one one-to-many collection relationship 
> •setting both sides of a one-to-one relationship such that they do not 
> refer to each 
> other 
> </spec>
>
>
> Craig Russell
>
> Architect, Sun Java Enterprise System http://java.sun.com/products/jdo
>
> 408 276-5638 mailto:Craig.Russell@sun.com
>
> P.S. A good JDO? O, Gasp!
>
>


Mime
  • Unnamed multipart/mixed (inline, None, 0 bytes)
View raw message