public abstract class SRecordInstance
extends java.lang.Object
implements java.io.Serializable
RecordInstances are normally created by either findOrCreate
or
SSessionJdbc#Query
. The former selects a specific record by primary key, while the latter retrieves all
records that satify a query. Instances may also be directly created by without
reference to a session.
The main methods are get*
and set*
which get and set field values of the record.
deleteRecord()
deletes a row.
No two RecordInstances can have the same primary key field values within the same connection. Attempts to retrieve the same row twice will simple return a pointer to an existing SRecordInstance. There is no relationship between RecordInstances in different connections -- all locking is done by the underlying database.
Modifier and Type | Class and Description |
---|---|
static class |
SRecordInstance.BrokenOptimisticLockException
Exception thrown due to broken optimistic locks.
|
Modifier | Constructor and Description |
---|---|
protected |
SRecordInstance()
Protected default constructor.
|
Modifier and Type | Method and Description |
---|---|
java.lang.String |
allFields()
For debugging like toString(), but shows all the fields.
|
void |
assertNewRow()
Throws an excpetion if !
isNewRow() . |
void |
assertNotNewRow() |
void |
defineInitialValue(SFieldMeta field)
Defines the current value of the field to be the initial value, which is then used for optimistic locks etc.
|
void |
deleteRecord()
Sets a flag to delete this record when the transaction is commited.
|
void |
doQueryRecord() |
void |
doValidateRecord() |
boolean |
equals(java.lang.Object key2)
Determines whehter two SRecordInstances are for the same SRecordMeta and have the same primary key fields.
|
<T extends SRecordInstance> |
findReference(SFieldReference<T> field) |
<T extends SRecordInstance> |
findReference(SFieldReference<T> field,
SQueryMode queryMode) |
<T extends SRecordInstance> |
findReference(SFieldReference<T> field,
SQueryMode queryMode,
SSelectMode selectMode)
Gets a record referenced by
this.field . |
<T extends SRecordInstance> |
findReference(SFieldReference<T> field,
SSelectMode selectMode) |
java.math.BigDecimal |
getBigDecimal(SFieldMeta field)
etc.
|
boolean |
getBoolean(SFieldMeta field)
Returns false if null.
|
byte[] |
getBytes(SFieldMeta field)
Casts getObject() to byte[].
|
SDataSet |
getDataSet() |
java.sql.Date |
getDate(SFieldMeta field)
etc.
|
double |
getDouble(SFieldMeta field)
Casts getObject() to double iff a Number, see getString().
|
<T extends java.lang.Enum<T>> |
getEnum(SFieldEnum<T> field) |
java.lang.Object |
getInitialValue(SFieldMeta fieldMeta)
The value that was read from (or flushed to) the database.
|
int |
getInt(SFieldMeta field)
Casts getObject() to int iff a Number, see getString().
|
SLog |
getLogger() |
long |
getLong(SFieldMeta field)
Casts getObject() to long iff a Number, see getString().
|
abstract SRecordMeta<?> |
getMeta()
This must be defined in every user record's definition to access the SRecord which provides the meta data for
this instance.
|
java.lang.Object |
getObject(SFieldMeta field)
Returns the field's value as a Java Object in the type stored in the dataset.
|
java.lang.Object |
getRawArrayValue(SFieldMeta fmeta)
Raw accessor for field value.
|
java.lang.Object |
getReferenceNoQuery(SFieldReference field)
Get a reference, but do not query either the dataset or the database.
|
java.lang.String |
getString(SFieldMeta field)
Gets the value of field cast to a String, trimed of trailing spaces.
|
java.sql.Time |
getTime(SFieldMeta field)
etc.
|
java.sql.Timestamp |
getTimestamp(SFieldMeta field)
etc.
|
int |
hashCode()
See
equals() . |
boolean |
isAttached()
True if this instance is attached to the current begun transaction.
|
boolean |
isDeleted() |
boolean |
isDirty()
True iff this record is dirty but not yet flushed to the database.
|
boolean |
isDirty(SFieldMeta field)
Tests whether just field is dirty.
|
boolean |
isEmpty(SFieldMeta field)
True if field is the empty value, ie.
|
boolean |
isNewRow()
Often called after {SRecordMeta#findOrCreate} to determine whether a row was retrieved from the database (not a
new row) or whether this record represents a new row that will be inserted when it is flushed.
|
boolean |
isNotDestroyed()
True if the record has valid data, ie.
|
boolean |
isNull(SFieldMeta field)
Was the field SQL NULL in the database? (eg.
|
boolean |
isReadOnly() |
boolean |
isValid(SFieldMeta field)
True if the field has been queried as part of the current transaction and so a get is valid.
|
protected void |
onQueryRecord()
Override this to get field values just after a record is actually retrieved, by findOrCreate or query.
|
protected void |
onValidateField(SFieldMeta field,
java.lang.Object newValue)
Called after individual field validators each time a field's value is set, (now) including keys.
|
protected void |
onValidateRecord()
Override this to validate records before flush.
|
void |
setBigDecimal(SFieldMeta field,
java.math.BigDecimal value) |
void |
setBoolean(SFieldMeta field,
boolean value) |
void |
setBytes(SFieldMeta field,
byte[] value) |
void |
setDate(SFieldMeta field,
java.util.Date value)
See
setTimestamp(simpleorm.dataset.SFieldMeta, java.util.Date) for discussion of Date parameter. |
void |
setDirty(boolean val)
Sets this record to be dirty so that it will be updated in the database.
|
void |
setDouble(SFieldMeta field,
double value) |
void |
setEmpty(SFieldMeta field)
Sets field to be empty, ie.
|
<T extends java.lang.Enum<T>> |
setEnum(SFieldEnum<T> field,
java.lang.Enum<T> value) |
void |
setInt(SFieldMeta field,
int value) |
void |
setLong(SFieldMeta field,
long value) |
void |
setNewRow(boolean val) |
void |
setNull(SFieldMeta field) |
void |
setObject(SFieldMeta field,
java.lang.Object value)
Generic routine to set a fields value.
|
void |
setObject(SFieldMeta field,
java.lang.Object value,
boolean fieldValidate)
Enables value to be set with field validation suppressed, rarely used.
|
void |
setRawArrayValue(SFieldMeta fmeta,
java.lang.Object value)
Raw setter for field value.
|
void |
setReadOnly(boolean val) |
void |
setReference(SFieldReference<?> field,
SRecordInstance value) |
void |
setString(SFieldMeta field,
java.lang.String value)
Sets the value of the field from a string, casting if necessary.
|
void |
setTime(SFieldMeta field,
java.util.Date value)
See
setTimestamp(simpleorm.dataset.SFieldMeta, java.util.Date) for discussion of Date parameter. |
void |
setTimestamp(SFieldMeta field,
java.util.Date value)
Note that value should normally be a java.sql.Timestamp (a subclass of java.util.Date).
|
java.lang.String |
toString()
toString just shows the Key field(s).
|
void |
validatePrimaryKeys() |
boolean |
wasInCache()
Was in the cache before the most recent findOrCreate.
|
protected SRecordInstance()
public abstract SRecordMeta<?> getMeta()
SRecord getMeta() { return meta; };
The actual meta
variable is thus not Serialized, but it would not be anyway as it is usually static.
public boolean equals(java.lang.Object key2)
This is purely for the purpose of putting SRecordInstances
in the
SSession.transactionCache
. This is done as tc.put(SRecordInstance, SRecordInstance)
,
ie the instance is used for both the key and the body. This avoids having to create a separate primary key
object for each record instance.
It only foreign keys, not referenced SRecordInstances which may be null if the parent record has not been retrieved.
equals
in class java.lang.Object
public int hashCode()
equals()
.hashCode
in class java.lang.Object
public java.lang.Object getObject(SFieldMeta field)
Methods such as getString()
dispach to this method but are generally more convenient because the
cast the result to the correct type. This method in turn just dispaches to field.getFieldValue()
,
ie. it is the declaredtype of the SField that determines how the value is retrieved.
Also lazily fetches referenced records if field is a reference. But findReference normally used instead. Don't rely on null result, as it could mean field is null, or it has not been queried or set. Use isNull(field) instead.
Enums are now stored as enums.
public void setObject(SFieldMeta field, java.lang.Object value)
field.setFieldValue(convertToField(value))
public void setObject(SFieldMeta field, java.lang.Object value, boolean fieldValidate)
public boolean isNull(SFieldMeta field)
public void setNull(SFieldMeta field)
public boolean isEmpty(SFieldMeta field)
SFieldFlags.SMANDATORY
public void setEmpty(SFieldMeta field)
setObject(,
null)
. But other options will be added later.SFieldFlags.SMANDATORY
public java.lang.String getString(SFieldMeta field)
getObject().toString().trimTrailingSpaces()
. So the field type itself need not be
SFieldString
, but just something that can be cast to a String. Trailing spaces can be a problem with
some databases and fileds declared CHAR
.
Note that if you do not want trailing spaces trimmed, then just call getObject().toString() manually. (For CHAR fields, most dbs/jdbc drivers seem to trim, but this is highly inconsistent.)
## Trimming is an issue with CHAR style fields that pad with spaces. Currently we always read from database into the fields without trimming. The idea being to let the SimpleORM user get at the raw query result using getObject, whatever that raw result is.
Most DBs seem to trim for us. But some may not, and some may require the trailing spaces on queries. Certainly trailing spaces in the objects will upset the record cache, and there is some dubious code in SRecordFinder.retrieveRecord() to handle this.
I think that for CHAR fields we need to always trim at database read, and pad where needed. This should also be dispatched to DB handler. I think that Oracle gives grief. (Note that trim means trailing spaces, leading should be left alone.)
I have not done this because it would require testing on many datbases.
public void setString(SFieldMeta field, java.lang.String value)
public int getInt(SFieldMeta field)
public void setInt(SFieldMeta field, int value)
public long getLong(SFieldMeta field)
public void setLong(SFieldMeta field, long value)
public double getDouble(SFieldMeta field)
public void setDouble(SFieldMeta field, double value)
public boolean getBoolean(SFieldMeta field)
public void setBoolean(SFieldMeta field, boolean value)
public java.sql.Timestamp getTimestamp(SFieldMeta field)
public void setTimestamp(SFieldMeta field, java.util.Date value)
public java.sql.Date getDate(SFieldMeta field)
public void setDate(SFieldMeta field, java.util.Date value)
setTimestamp(simpleorm.dataset.SFieldMeta, java.util.Date)
for discussion of Date parameter.public java.sql.Time getTime(SFieldMeta field)
public void setTime(SFieldMeta field, java.util.Date value)
setTimestamp(simpleorm.dataset.SFieldMeta, java.util.Date)
for discussion of Date parameter.public java.math.BigDecimal getBigDecimal(SFieldMeta field)
public void setBigDecimal(SFieldMeta field, java.math.BigDecimal value)
public <T extends java.lang.Enum<T>> T getEnum(SFieldEnum<T> field)
public <T extends java.lang.Enum<T>> void setEnum(SFieldEnum<T> field, java.lang.Enum<T> value)
public byte[] getBytes(SFieldMeta field)
public void setBytes(SFieldMeta field, byte[] value)
public <T extends SRecordInstance> T findReference(SFieldReference<T> field, SQueryMode queryMode, SSelectMode selectMode)
this.field
. Does a lazy lookup on the SDataSet.getSession() if
necessary, and if attached to a session.
If the field is null but all the primary key fields are non null then does a dataset.find()
and if
necessary a SSessionI.findOrCreate()
to provide a referenced record.
public <T extends SRecordInstance> T findReference(SFieldReference<T> field, SSelectMode selectMode)
public <T extends SRecordInstance> T findReference(SFieldReference<T> field, SQueryMode queryMode)
public <T extends SRecordInstance> T findReference(SFieldReference<T> field)
public void setReference(SFieldReference<?> field, SRecordInstance value)
public java.lang.Object getReferenceNoQuery(SFieldReference field)
public void setDirty(boolean val)
NOP - But may occasionally be useful after a findOrInsert() to add a record that contains nothing appart from its primary key. ===> isNewRow is here for that
public boolean isDirty()
A record is not dirty if a record has been flushed to the database but the transaction not committed.
## Should add wasEverDirty method for both record and fields for validation tests.
public boolean isDirty(SFieldMeta field)
public boolean wasInCache()
public void deleteRecord()
findOrCreate
will thus return the deleted record but its fields may
not be referenced. (isDeleted
can be used to determine that the record has been deleted.)
The record is only deleted from the database when the transaction is committed or is flushed. Thus a transaction that nulls out references to a parent record and then deletes the parent record will not cause a referential integrity violation because the update order is preserved so that the updates will (normally) be performed before the deletes.
Note that for Optimistic locks only those fields that were retrieved are checked for locks.
public boolean isDeleted()
public boolean isNewRow()
public void setNewRow(boolean val)
public void assertNewRow()
isNewRow()
. Handy, use often in your code to trap nasty errors.public void assertNotNewRow()
assertNewRow()
public boolean isNotDestroyed()
public boolean isValid(SFieldMeta field)
public boolean isAttached()
public java.lang.String toString()
toString
in class java.lang.Object
public java.lang.String allFields()
protected void onValidateField(SFieldMeta field, java.lang.Object newValue)
Throw an SException.Validation if not OK. The value is not assigned, and the transaction can continue. The exception will be augmented with
This is called after the value has been converted to its proper type, eg. from a String to a Double and the field value has been updated.
If the validation fails, the field is automatically set back to its oldValue.
This is called for key values as well. This is only for newly created records but is during the findOrCreate -- ie it is called even if the record is never made dirty and thus saved.
public void doValidateRecord()
protected void onValidateRecord()
This is called just before a record would be flushed. Only dirty records are validated. If the validation fails then the record is not flushed. (It may also be called directly by the application to validate the record before it is flushed.)
Use this routine when a record may be in a temporarily invalid state, but which must be corrected before flushing. This is common when there is a more complex relationship between different fields that cannot be validated until all the fields have been assigned values.
protected void onQueryRecord()
public void doQueryRecord()
public void validatePrimaryKeys()
public void setRawArrayValue(SFieldMeta fmeta, java.lang.Object value)
fmeta
- the field to setvalue
- the new value of the field, as is, can be nullpublic java.lang.Object getRawArrayValue(SFieldMeta fmeta)
fmeta
- the field to getpublic java.lang.Object getInitialValue(SFieldMeta fieldMeta)
public void defineInitialValue(SFieldMeta field)
public SLog getLogger()
public boolean isReadOnly()
public void setReadOnly(boolean val)
public SDataSet getDataSet()