Class SRecordInstance

  • All Implemented Interfaces:
    java.io.Serializable
    Direct Known Subclasses:
    PersistentRecord

    public abstract class SRecordInstance
    extends java.lang.Object
    implements java.io.Serializable
    Each SRecordInstance represents an individual record in memory that either correspond to a row in the database or a new record that has yet to be inserted.

    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.

    See Also:
    Serialized Form
    • Constructor Detail

      • SRecordInstance

        protected SRecordInstance()
        Protected default constructor. Necessary to allow definition of record with no explicit constructor. If overriding is REALLY necessary, don't forget to call super();
    • Method Detail

      • getMeta

        public 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. It is normally defined as:-

         SRecord getMeta() {
           return meta;
         };
         

        The actual meta variable is thus not Serialized, but it would not be anyway as it is usually static.

      • equals

        public boolean equals​(java.lang.Object key2)
        Determines whehter two SRecordInstances are for the same SRecordMeta and have the same primary key fields.

        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.

        Overrides:
        equals in class java.lang.Object
      • hashCode

        public int hashCode()
        See equals().
        Overrides:
        hashCode in class java.lang.Object
      • getObject

        public java.lang.Object getObject​(SFieldMeta field)
        Returns the field's value as a Java Object in the type stored in the dataset.

        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.

      • setObject

        public void setObject​(SFieldMeta field,
                              java.lang.Object value)
        Generic routine to set a fields value. Just dispaches to field.setFieldValue(convertToField(value))

      • setObject

        public void setObject​(SFieldMeta field,
                              java.lang.Object value,
                              boolean fieldValidate)
        Enables value to be set with field validation suppressed, rarely used.
      • isNull

        public boolean isNull​(SFieldMeta field)
        Was the field SQL NULL in the database? (eg. getInt would return 0 for this case.) Does not need to do query for reference fields, just checks if any refing scalars are null.
      • setNull

        public void setNull​(SFieldMeta field)
      • setEmpty

        public void setEmpty​(SFieldMeta field)
        Sets field to be empty, ie. currently setObject(, null). But other options will be added later.
        See Also:
        SFieldFlags.SMANDATORY
      • getString

        public java.lang.String getString​(SFieldMeta field)
        Gets the value of field cast to a String, trimed of trailing spaces. This is equivalent to 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.

      • setString

        public void setString​(SFieldMeta field,
                              java.lang.String value)
        Sets the value of the field from a string, casting if necessary. So this can be used to set an Integer field, say.
      • getInt

        public int getInt​(SFieldMeta field)
        Casts getObject() to int iff a Number, see getString(). Returns 0 if null, following JDBC.
      • setInt

        public void setInt​(SFieldMeta field,
                           int value)
      • getLong

        public long getLong​(SFieldMeta field)
        Casts getObject() to long iff a Number, see getString(). Returns 0 if null, following JDBC. Note that longs may not be accurately supported by the database -- see SFieldLong.
      • setLong

        public void setLong​(SFieldMeta field,
                            long value)
      • getDouble

        public double getDouble​(SFieldMeta field)
        Casts getObject() to double iff a Number, see getString(). Returns 0 if null, following JDBC.
      • setDouble

        public void setDouble​(SFieldMeta field,
                              double value)
      • getBoolean

        public boolean getBoolean​(SFieldMeta field)
        Returns false if null.
      • setBoolean

        public void setBoolean​(SFieldMeta field,
                               boolean value)
      • getTimestamp

        public java.sql.Timestamp getTimestamp​(SFieldMeta field)
        etc. for Timestamp.
      • setTimestamp

        public void setTimestamp​(SFieldMeta field,
                                 java.util.Date value)
        Note that value should normally be a java.sql.Timestamp (a subclass of java.util.Date). However, if it is a java.util.Date instead, then it will replaced by a new java.sql.Timestamp object before being set. This is convenient for people using java.util.Date as their main date type.
      • getDate

        public java.sql.Date getDate​(SFieldMeta field)
        etc. for Date. ### Should convert strings to Date, ISO etc. Likewise other types. (Painful to do in Java!)
      • getTime

        public java.sql.Time getTime​(SFieldMeta field)
        etc. for Time.
      • getBigDecimal

        public java.math.BigDecimal getBigDecimal​(SFieldMeta field)
        etc. for BigDecimal.
      • setBigDecimal

        public void setBigDecimal​(SFieldMeta field,
                                  java.math.BigDecimal value)
      • getEnum

        public <T extends java.lang.Enum<T>> T getEnum​(SFieldEnum<T> field)
      • setEnum

        public <T extends java.lang.Enum<T>> void setEnum​(SFieldEnum<T> field,
                                                          java.lang.Enum<T> value)
      • getBytes

        public byte[] getBytes​(SFieldMeta field)
        Casts getObject() to byte[].
      • setBytes

        public void setBytes​(SFieldMeta field,
                             byte[] value)
      • findReference

        public <T extends SRecordInstance> T findReference​(SFieldReference<T> field,
                                                           SQueryMode queryMode,
                                                           SSelectMode selectMode)
        Gets a record referenced by 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.

      • getReferenceNoQuery

        public java.lang.Object getReferenceNoQuery​(SFieldReference field)
        Get a reference, but do not query either the dataset or the database. Returns null if a corresponding scalar field is null. Returns Boolean.FALSE if it is not null, but has not been queried from the database.
      • setDirty

        public void setDirty​(boolean val)
        Sets this record to be dirty so that it will be updated in the database. Normally done implicitly by setting a specific column.

        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

      • isDirty

        public boolean isDirty()
        True iff this record is dirty but not yet flushed to the database. May be both dirty and unattached.

        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.

      • isDirty

        public boolean isDirty​(SFieldMeta field)
        Tests whether just field is dirty.
      • wasInCache

        public boolean wasInCache()
        Was in the cache before the most recent findOrCreate. (Will always been in the cache after a findOrCreate.) Used to prevent two create()s for the same key. Also for unit tests.
      • deleteRecord

        public void deleteRecord()
        Sets a flag to delete this record when the transaction is commited. The record is not removed from the transaction cache. Any future 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.

      • isDeleted

        public boolean isDeleted()
      • isNewRow

        public 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.
      • setNewRow

        public void setNewRow​(boolean val)
      • assertNewRow

        public void assertNewRow()
        Throws an excpetion if !isNewRow(). Handy, use often in your code to trap nasty errors.
      • assertNotNewRow

        public void assertNotNewRow()
        See Also:
        assertNewRow()
      • isNotDestroyed

        public boolean isNotDestroyed()
        True if the record has valid data, ie. it has not been destroyed. (This has nothing to do with validateRecord.)
      • isValid

        public boolean isValid​(SFieldMeta field)
        True if the field has been queried as part of the current transaction and so a get is valid. Use this to guard validations if partial column queries are performed. See isDirty.
      • isAttached

        public boolean isAttached()
        True if this instance is attached to the current begun transaction. Exception if is attached but not to the current transaction or the current transaction has not begun. #### not right.
      • toString

        public java.lang.String toString()
        toString just shows the Key field(s). It is meant to be consise, often used as part of longer messages.
        Overrides:
        toString in class java.lang.Object
      • allFields

        public java.lang.String allFields()
        For debugging like toString(), but shows all the fields.
      • onValidateField

        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. Not called as values are retrieved from database.

        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.

      • doValidateRecord

        public void doValidateRecord()
      • onValidateRecord

        protected void onValidateRecord()
        Override this to validate records before flush. Throw an SValidationException if not OK.

        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.

      • onQueryRecord

        protected void onQueryRecord()
        Override this to get field values just after a record is actually retrieved, by findOrCreate or query.
      • doQueryRecord

        public void doQueryRecord()
      • validatePrimaryKeys

        public void validatePrimaryKeys()
      • setRawArrayValue

        public void setRawArrayValue​(SFieldMeta fmeta,
                                     java.lang.Object value)
        Raw setter for field value. Internal to Simpleorm. Assigns directly into the array of values. No validation or conversion.
        Parameters:
        fmeta - the field to set
        value - the new value of the field, as is, can be null
      • getRawArrayValue

        public java.lang.Object getRawArrayValue​(SFieldMeta fmeta)
        Raw accessor for field value. Internal to Simpleorm. Gets directly from the array of values. No findReference. No Valid test.
        Parameters:
        fmeta - the field to get
      • getInitialValue

        public java.lang.Object getInitialValue​(SFieldMeta fieldMeta)
        The value that was read from (or flushed to) the database. Used for optimistic locking, and also just to tell how fields change.
      • defineInitialValue

        public void defineInitialValue​(SFieldMeta field)
        Defines the current value of the field to be the initial value, which is then used for optimistic locks etc. Called just after a record is read or updated.

      • getLogger

        public SLog getLogger()
      • isReadOnly

        public boolean isReadOnly()
      • setReadOnly

        public void setReadOnly​(boolean val)
      • getDataSet

        public SDataSet getDataSet()