| java.lang.Object simpleorm.properties.SPropertyMap simpleorm.core.SFieldMeta simpleorm.core.SFieldReference
SFieldReference | public class SFieldReference extends SFieldMeta (Code) | | Represents a foreign key reference from one record to another. It's
initializer also normally generates the implicit foreign key fields.
For example, assume that Employee has a
DEPT_ID field that refers to
Department.DEPT_ID . The Employee record
would normally be declared as follows:-
public class Employee extends SRecordInstance...
static final SFieldMeta DEPARTMENT =
new SFieldReference(meta, Department.meta);
Internally the DEPARTMENT Reference generates one
or more Foreign Key fields that correspond to each key fields
in Department . In the example above, an implicit
Employee.DEPT_ID field would be created. Note that if
the key defintion of Department changed then this would
be automatically propogated to the Employee record.
It is also possible to declare the foreign key fields explicitly,
which enables extra parameters such as column names to be explicitly
specified. For example:-
public class Employee extends SRecordInstance...
public static final SFieldMeta DEPT_ID =
new SFieldString(meta, "DEPT_ID");
static final SFieldMeta DEPARTMENT = new
SFieldReference(meta, Department.meta,
new SFieldMeta[]{DEPT_ID}, 0);
References are also allowed in primary keys of records, these are
known as Identifying foreign keys. This means that additional
foreign keys would be added recursively. See
for examples.
Explicitly storing the foreign key fields means that there
is no need to have a Department record instance in order
to retrieve an Employee . Only if one calls
Employee.getDepartment is the Department
record created. It also alows overlapping foreign keys to be
supported later (where two References may share a column).
Fields are normally created in static initializers of class constants
(although this is not necessary). The java initialization rules
generally work well to ensure that referenced records are initialized
before referencing records. However, it may occasionally be necessary
to create references in a second pass, particularly if there are
mutually recursive references.
To understand the underlying data structures you really need to look
at the E-R diagram.
E-Mail Extracts:-
First of all let me note that the problem that you are dealing with is the mapping what used to be called a conceptual model and the relational/logical model. In the traditional "three schema model" generators work from conceptual through logical to physical models.
Since the advent of OO technology, the words have changed but the problems remain the same. Generating the relational schema from the conceptual one used by SimpleORM is quite fiddly, and is the most complex code in SimpleORM. Going the other way is, in general, much harder -- you are squeezing the toothpaste back into a tube, and not necessarily the same type of tube from whence it came.
However, in your quick start you do not have to solve all problems. Just generate the easy, common cases. Remember that the user can add foreign key definition in their subclass -- there is no reflection. So please focus on the simple, consistent cases.
As Richard implies, it is a fundamental assumtion of SimpleORM that records only contain one Primary key, and that that all foreign keys use it. No candidate keys considered. This is pretty fundamental to the way SimpleORM works -- the cache is keyed by the primary key, only.
So that is why you only need to specify the referencing record, but may in general have to specify all the referencing fields. This is why fields are *not* specified as
SFieldReference(SRecordMeta meta, SFieldMeta[] localKeys, SFieldMeta[] foreignKeys)
which is a relational approach.
SimpleORM assumes that foreign keys are generally defined in a consistent manner. This produces succinct code. I have not tried to make the processing of inconsistent names elegant because I assume (wrongly?) that it is rare.
|
Constructor Summary | |
public | SFieldReference(SRecordMeta meta, SRecordMeta referenced, String fieldName, SFieldMeta[] foreignKeys, SPropertyValue[] pvals) Creates a foreign key reference using foreignKeys
to reference referenced . | public | SFieldReference(SRecordMeta meta, SRecordMeta referenced, SFieldMeta[] foreignKeys, SPropertyValue[] pvals) | public | SFieldReference(SRecordMeta meta, SFieldReference referenced, String fieldName, SFieldMeta[] foreignKeys, SPropertyValue[] pvals) Same as above, but used to reference intermediate foreign keys. | public | SFieldReference(SRecordMeta meta, SFieldReference referenced, SFieldMeta[] foreignKeys, SPropertyValue[] pvals) | public | SFieldReference(SRecordMeta meta, SRecordMeta referenced, String prefix, SPropertyValue[] pvals) Creates a SFieldReference field to reference
referenced . | public | SFieldReference(SRecordMeta meta, SRecordMeta referenced, String prefix, SPropertyValue pval1) | public | SFieldReference(SRecordMeta meta, SRecordMeta referenced, String prefix, SPropertyValue pval1, SPropertyValue pval2) | public | SFieldReference(SRecordMeta meta, SRecordMeta referenced, String prefix) | public | SFieldReference(SRecordMeta meta, SRecordMeta referenced) prefix defaults to "", the common case. | public | SFieldReference(SRecordMeta meta, SFieldReference referenced, String prefix, SPropertyValue[] pvals) For identifying foreign keys. |
foreignKeyFields | SFieldMeta[] foreignKeyFields(Code) | | The direct foreign keys, may not all be scalars. True inverse
of SFieldMeta.sFieldReference . Not a flattened
structure like SRecordMeta.sFieldMetas. You have to recur to
get all the scalar fields in a reference.
|
prefix | String prefix(Code) | | This is the string prepended to any foreign keys. Eg. to
distinquish ACTING_DEPT_ID vs
PERMANENT_DEPT_ID .
|
referencedRecord | SRecordMeta referencedRecord(Code) | | The ultmatiley referenced record whose keys correspond to this
reference's foreign keys. Ie. the end of the chain. Not the
same as foreignKeyFields[0].sRecordMeta which is
just one level deep. SFieldMeta.referencedKeyField
points to correpsonding reference in the
foreignKeyFields[0].sRecordMeta record.
|
SFieldReference | public SFieldReference(SRecordMeta meta, SRecordMeta referenced, String fieldName, SFieldMeta[] foreignKeys, SPropertyValue[] pvals)(Code) | | Creates a foreign key reference using foreignKeys
to reference referenced . The foreignKeys
must match the top level primarky keys of referenced
exactly in order, type and number. If the primaryKey includes
references, then just the reference should be included, not the
indirect foreign keys.
This raw initializer is only useful to add extra specifications to
the explicit definitions of the foreign key fields. This is rare in
practice.
|
SFieldReference | public SFieldReference(SRecordMeta meta, SRecordMeta referenced, String prefix, SPropertyValue[] pvals)(Code) | | Creates a SFieldReference field to reference
referenced . Then creates aditiaonal SFieldMetas that
correspond each column of the foreign key. A foreign key may in
turn be a reference ("Identifying" foreign key) in which case
this process recurs.
Each created foreign key column has the same name and type as
the one in the referenced table but the names can be prefixed by
prefix which is handy if for example, an Employee
had a Managing_Department and a Billing_Department.
|
checkUpdatable | void checkUpdatable(SRecordInstance instance)(Code) | | This reference is updatable iff all its ground foreign keys are
updatable, recursively.
|
defaultDataType | String defaultDataType()(Code) | | Specializes SFieldMeta.
|
foreignKeyField | public SFieldMeta foreignKeyField(int index)(Code) | | Returns the field definition of the index th foreign
key for this reference. The first one is 0. This can then be used
as a parameter to subsequent get*() methods.
The main use of this function is to access the foreing key values of
references without having to actually query the database.
(Note that
this purpose will become obsolete once the lazy
findOrCreate is implemented because just referencing
the key value of the referenced object will not trigger the
query.)
|
foreignKeyFieldsSize | public int foreignKeyFieldsSize()(Code) | | Number of foreign key fields for this reference.
|
getRawFieldValue | Object getRawFieldValue(SRecordInstance instance, long sqy_flags)(Code) | | Specializes SFieldMeta.getRawFieldValue, which is called by
getFieldValue, thence SRecoredInstance.getObject...
Normally, if the field is null but all the primary key fields
are non null then does a findOrCreate() to provide
a referenced record. SQY_REFERENCE_NO_QUERY suppresses this
query. getReferencedWhileDetached may be called for detached
records.
|
getReferencedRecord | public SRecordMeta getReferencedRecord()(Code) | | Get the SRecordMeta to which this reference points to.
Will not attempt to retrieve the record from the database,
will return null if not in memory.
|
rawSetFieldValue | void rawSetFieldValue(SRecordInstance instance, Object value)(Code) | | Sets the instance reference to value. Then recursively copies
all of the foreign keys. this must be a top level
foreign key. (value could be null.)
|
|
|