db-jdo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Matthew Adams" <matthew.ad...@xcalia.com>
Subject RE: Relationships mapped with mapped-by (long)
Date Fri, 08 Sep 2006 18:31:36 GMT
The scenario that we discussed on the phone for which I had an action
item is already addressed in the specification, section 15.3, paragraph
6, bullet point 2:
 
"Conflicting changes include...setting both sides of a one-to-one
relationship such that they do not refer to each other"
 
No spec update is required to handle the scenario where E is updated to
refer to V then V is updated to refer to something other than E.
 
--matthew


________________________________

	From: Craig.Russell@Sun.COM [mailto:Craig.Russell@Sun.COM] 
	Sent: Tuesday, September 05, 2006 1:29 PM
	To: JDO Expert Group; Apache JDO project
	Subject: Relationships mapped with mapped-by (long)
	
	
	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/alternative (inline, None, 0 bytes)
View raw message