Workspace 6.21.5
Public Member Functions | Protected Member Functions | List of all members
SqlBoundObjectGroup Class Referenceabstract

An SqlBoundObjectGroup class is bound to a specific SQL table or view, and its instance objects are bound to individual records from this table or view. More...

#include <DataAnalysis/DataStructures/sqlboundobjectgroup.h>

Inheritance diagram for SqlBoundObjectGroup:
[legend]

Public Member Functions

 ~SqlBoundObjectGroup () override
 
SqlBoundObjectGroupclone () const override=0
 
virtual SqlBoundObjectGroupdeepCopy () const =0
 
void detach (bool recursive=false)
 
QStringList getAutoIncrementFieldNames () const
 
QString getBoundTableName () const
 
QStringList getCompositePrimaryKeyFieldNames () const
 
QStringList getCompositePrimaryKeyFieldNamesAliased () const
 
QString getFieldName (const DataExecution::DataObject &object) const
 
QStringList getNonRelationFieldAliases () const
 
QStringList getNonRelationFieldNames () const
 
DataExecution::DataObjectgetPrimaryKeyField ()
 
const DataExecution::DataObjectgetPrimaryKeyField () const
 
QString getPrimaryKeyFieldName () const
 
QString getPrimaryKeyFieldNameAliased () const
 
SqlBindingRelationMap getRelationBindings (const QStringList &relationNames=QStringList(), bool recursive=false) const
 
QStringList getRelationFieldNames (bool recursive) const
 
QStringList getSqlValidCompositePrimaryKeyFieldNames () const
 
QStringList getSqlValidFieldList () const
 
bool hasCompositePrimaryKey () const
 
bool isPersistent () const
 
bool isPrimaryKeyField (const DataExecution::DataObject &obj) const
 
bool isRelationField (const QString &fieldName) const
 
void setPersistent (bool b)
 
- Public Member Functions inherited from ObjectGroup
 ~ObjectGroup () override
 
bool add (const QString &name, DataObject &obj)
 
bool canSerialize () const override
 
ObjectGroupclone () const override=0
 
bool empty () const
 
void ensureGroupHasData ()
 
void erase (int index)
 
DataObjectgetChild (const QString &name)
 
const DataObjectgetChild (const QString &name) const
 
DataObjectgetDataObject (int index)
 
const DataObjectgetDataObject (int index) const
 
int getIndex (const QString &name) const
 
const QString & getName (int index) const
 
virtual QString getPreferedWidget (const QString &name) const
 
bool hasData () const
 
bool haveName (const QString &name) const
 
bool insert (const QString &name, DataObject &obj, int index=-1)
 
bool load (const QJsonDocument &doc)
 
bool load (const SerializedItem &item) override
 
bool save (QJsonDocument &doc) const
 
bool save (SerializedItem &item) const override
 
unsigned size () const
 
- Public Member Functions inherited from Clonable
virtual ~Clonable ()=default
 
virtual Clonableclone () const =0
 
- Public Member Functions inherited from Serialize
virtual ~Serialize ()=default
 
virtual bool canSerialize () const =0
 
virtual bool load (const SerializedItem &item)=0
 
virtual bool save (SerializedItem &item) const =0
 

Protected Member Functions

 SqlBoundObjectGroup (const SqlBoundObjectGroup &other)
 
 SqlBoundObjectGroup (SqlBoundObjectGroupData *data)
 
bool bindCompositePrimaryKey (const QList< const DataExecution::DataObject * > &objects)
 
bool bindField (const QString &fieldName, DataExecution::DataObject &object)
 
bool bindRelation (const SqlBindingRelation &relation)
 
virtual const SqlBoundObjectClassDatagetClassData () const =0
 
virtual QSqlQuery getInsertQuery (const SqlDataModel &model, const QStringList &relations, const QString &foreignKeyName=QString(), const QVariant &foreignKeyValue=QVariant()) const =0
 
virtual QSqlQuery getUpdateQuery (const SqlDataModel &model, const QStringList &relations, const QString &foreignKeyName=QString(), const QVariant &foreignKeyValue=QVariant()) const =0
 
SqlBoundObjectGroupoperator= (const SqlBoundObjectGroup &)
 
bool operator== (const SqlBoundObjectGroup &rhs) const
 
bool setPrimaryKeyField (const DataExecution::DataObject &obj, bool autoIncrement)
 
- Protected Member Functions inherited from ObjectGroup
 ObjectGroup ()
 
void clear ()
 
ObjectGroupoperator= (const ObjectGroup &rhs)
 
bool operator== (const ObjectGroup &rhs) const
 
void swap (ObjectGroup &rhs)
 

Detailed Description

This SqlBoundObjectGroup is the base class of all ObjectGroup types that are "bound" to a specific database table or view. Bound objects represent a record from the table, and each of their data members is contain a single field of data from the record.

Bound objects represent a statically typed interface to a database record, which can have a number of advantages over using the Qt SQL classes directly (QSqlQuery and QSqlRecord):

- When the database structure changes, the code structure can be easily updated,
  as all database interaction is via a well-defined, compiled interface, rather than
  string literals that are assumed to be SQL statements.
- Data types are all enforced via the statically typed interface, which saves on
  validation effort and reduces the risk of bad data being written to the database.

The downside of using this statically typed interface is:

- There is less flexibility that writing a completely custom query and processing
  the results in a custom fashion. There are some things possible with custom
  queries and manual data processing that can not be done using this static interface.

To create a specific type of SqlBoundObjectGroup, developers must create a new class deriving from TypedSqlBoundObjectGroup and in its constructor, specify the appropriate data field, primary key and relation bindings. For example, here is an "Author" class, which has a many-to-many relationship with the "Book" class, and a many-to-one relationship with the "Publisher" class:

```
class Author : public DataAnalysis::TypedSqlBoundObjectGroup<Author, int>
{
public:
    DataExecution::TypedObject<IdType>       id;
    DataExecution::TypedObject<QString>      lastName;
    DataExecution::TypedObject<QString>      firstName;
    DataExecution::TypedObject<QString>      address;
    DataExecution::TypedObject<QString>      city;
    DataExecution::TypedObject<Publisher>    publisher;
    DataExecution::TypedObject<BookArray>    books;

    Author() : DataAnalysis::TypedSqlBoundObjectGroup<Author, int>()
    {
        bindField("Id", id);
        bindField("LastName", lastName);
        bindField("FirstName", firstName);
        bindField("Address", address);
        bindField("City", city);
        bindField("Publisher", publisher);
        bindField("Books", books);
        bindPrimaryKeyField(id);
       bindRelation(DataAnalysis::ManyToOneRelation<Testing::Publisher>(publisher, "Publisher_Id"));
       bindRelation(DataAnalysis::ManyToManyRelation<Testing::Book>(books, "Book_Id", "Author_Id", "Author_Book"));
    }

    Author(const Author& other) = delete;
    Author& operator=(const Author& rhs)
    {
       return TypedSqlBoundObjectGroup<Author,int>::operator=(rhs);
    }
};
Developers must also write appropriate DECLARE and DEFINE macros in the .h and .cpp files respectively:

DECLARE_WORKSPACE_SQL_DATA_FACTORIES(CSIRO::Testing::Author, CSIRO_TESTING_API) DEFINE_WORKSPACE_SQL_DATA_FACTORIES(CSIRO::Testing::Author, CSIRO::Testing::TestSqlDataModelPlugin::getInstance()) ```

Lastly, in order to ensure that the object is bound to the correct view or table, developers must implement a template specialisation of the SqlDataModel::getBoundTableName() function:

```
template<>
inline QString SqlDataModel::getBoundTableName<Testing::Author>()
{
    return "Author";
}

```

Once this has been done, SqlBoundObjectGroups can be retrieved from an instance of a SqlDataModel that is attached to a database conforming to the expected schema by using the relevant fetch() or save() function as required.

Note
SqlBoundObjectGroups are explicitly shared. This means that assigning one object to another, or creating a clone of an object will result in the two objects sharing a reference to the same underlying data. This allows objects that represent frequently referenced DB records (i.e. those records referred to multiple times via foreign keys in other tables) to be easily updated from any location, even if they are used multiple times in an object hierarchy. To modify an object refer to its own unique data, use the detach() function, or create a new object by using the deepCopy() function.
See also
TypedSqlBoundObjectGroup

Constructor & Destructor Documentation

◆ ~SqlBoundObjectGroup()

~SqlBoundObjectGroup ( )
override

◆ SqlBoundObjectGroup() [1/2]

Parameters
dataThe data which this bound object group will refer to. In general, this will be a newly constructed object created by a derived class, as this constructor is protected.

Creates a new SqlBoundObjectGroup referring to the specified object data. Multiple objects may share the same data, though this is managed through the assignment operator or copy constructor, not this protected constructor.

Note
The object group will take ownership of data.

◆ SqlBoundObjectGroup() [2/2]

SqlBoundObjectGroup ( const SqlBoundObjectGroup other)
protected
Parameters
otherThe other object to copy.

Creates a new SqlBoundObjectGroup which is a shallow copy of other, which is to say that it will share a reference to the same underlying data.

Member Function Documentation

◆ bindCompositePrimaryKey()

bool bindCompositePrimaryKey ( const QList< const DataExecution::DataObject * > &  objects)
protected
Parameters
objectsA list of child objects that comprise the composite primary key of this object.
Returns
True if the objects were bound successfully as the composite primary key. False is returned if any of the objects were not previously bound as fields of this object (see bindField().
See also
bindField()

◆ bindField()

bool bindField ( const QString &  fieldName,
DataExecution::DataObject object 
)
protected
Parameters
fieldNameThe name of the field in the underlying database (i.e. the column name)
objectThe member object that is going to contain the data associated with this field in the record represented by this object.
Returns
true if successful, false if an error occurs, such as if the specified field name is already bound to another object.

◆ bindRelation()

bool bindRelation ( const SqlBindingRelation relation)
protected
Parameters
relationThe SqlBindingRelation to bind to this object group.
Returns
true if the relation was able to be successfully bound, false if the relation is invalid (i.e. refers to an object that is not a child of this object, or refers to an object that is already bound to an existing relation).

Binds a specific relation to this object group. The relation links a specific child member of a type deriving from SqlBoundObjectGroup (or a TypedObjectArray of such derived class objects) to this object. It replaces the need for manually joining the objects to other tables in order to represent relationship data.

◆ clone()

SqlBoundObjectGroup * clone ( ) const
overridepure virtual
Returns
A shallow copy of our object: i.e. our data is shared between all objects of the same type. This is the default in order to allow easy distribution of the same object throughout an object hierarchy retrieved from a database.
See also
deepCopy

Implements ObjectGroup.

Implemented in InvalidSqlBoundObjectGroup, and TypedSqlBoundObjectGroup< Derived, PrimaryKeyType >.

◆ deepCopy()

virtual SqlBoundObjectGroup * deepCopy ( ) const
pure virtual
Returns
A deep copy of the object, with copies of of all underlying objects right down the entire object hierarchy. Use this when you want to copy an entire tree but deliberately do not want to modify any shared data.

Implemented in InvalidSqlBoundObjectGroup, and TypedSqlBoundObjectGroup< Derived, PrimaryKeyType >.

◆ detach()

void detach ( bool  recursive = false)
Parameters
recursiveWhether or not to detach child objects, and children of child objects etc.

Detaches this object from its shared data, creating a local copy of its data. Child objects will still be shared unless specified otherwise via the recursive parameter.

◆ getAutoIncrementFieldNames()

QStringList getAutoIncrementFieldNames ( ) const
Returns
A list of fields that have the auto-increment flag.

Most database types have support for auto-incrementing certain fields upon insert, usually integer type primary key fields. Some databases support multiple auto-increment fields on the same table. This function returns the list of auto-increment fields associated with this SqlBoundObjectGroup.

◆ getBoundTableName()

QString getBoundTableName ( ) const
Returns
Returns the name of the database table or view that this SqlBoundObjectGroup is bound to.

◆ getClassData()

virtual const SqlBoundObjectClassData & getClassData ( ) const
protectedpure virtual
Returns
The class data associated with this object, which includes information such as the bound table name etc.

Implemented in InvalidSqlBoundObjectGroup, and TypedSqlBoundObjectGroup< Derived, PrimaryKeyType >.

◆ getCompositePrimaryKeyFieldNames()

QStringList getCompositePrimaryKeyFieldNames ( ) const
Returns
A QStringList containing the field names of this object's composite primary key. If the object does not have a composite primary key, an empty QStringList is returned.
See also
hasCompositePrimaryKey()
getCompositePrimaryKeyFieldNamesAliased()
getSqlValidCompositePrimaryKeyFieldNames()

◆ getCompositePrimaryKeyFieldNamesAliased()

QStringList getCompositePrimaryKeyFieldNamesAliased ( ) const
Returns
Returns a QStringList containing the aliased field names of this object's composite primary key. If the object does not have a composite primary key, an empty QStringList is returned.

All object members, when used in an underlying Sql query, must be appropriately aliased so as to avoid naming conflicts. This function returns the aliased versions of the composite primary key field names.

See also
hasCompositePrimaryKey()
getCompositePrimaryKeyFieldNames()
getSqlValidCompositePrimaryKeyFieldNames()

◆ getFieldName()

QString getFieldName ( const DataExecution::DataObject object) const
Parameters
objectReference to the child object for which we wish to retrieve its field name.
Returns
The name of the field that this object is associated with. If the object does not exist as a child of this object, an empty string is returned.

◆ getInsertQuery()

virtual QSqlQuery getInsertQuery ( const SqlDataModel model,
const QStringList relations,
const QString &  foreignKeyName = QString(),
const QVariant &  foreignKeyValue = QVariant() 
) const
protectedpure virtual
Parameters
modelThe SqlDataModel responsible for the insertion operation.
relationsA list of relations to follow when generating the insert.
foreignKeyName(optional) The name of a foreign key field attached to the table that this object is bound to. Important for inserting objects with bi-directional relations.
foreignKeyValueThe value to store in the field named foreignKeyName when inserting this object.
Returns
A QSqlQuery that can be executed to insert this object into the database associated with model.

Returns the SQL query required to insert this particular object into a database. Callers should never need to invoke this method directly.

Implemented in TypedSqlBoundObjectGroup< Derived, PrimaryKeyType >, and InvalidSqlBoundObjectGroup.

◆ getNonRelationFieldAliases()

QStringList getNonRelationFieldAliases ( ) const
Returns
A list of all the field names used by this bound object, not including relation names. The field names are aliased so as to avoid conflicts with identically named fields from other tables.
See also
getNonRelationFieldNames()
getSqlValidFieldList()

◆ getNonRelationFieldNames()

QStringList getNonRelationFieldNames ( ) const
Returns
A list of all the field names used by this bound object, not including relation names.

This method is used to retrieve the list of all member fields that are bound directly to underlying database fields. Relation fields (i.e. fields that reference other SqlBoundObjectGroup types) are not included in the returned list. This allows calling code to differentiate between directly bound members, and members that contain data that is stored in related tables.

See also
getNonRelationFieldAliases()
getSqlValidFieldList()

◆ getPrimaryKeyField() [1/2]

DataExecution::DataObject & getPrimaryKeyField ( )
Returns
The data object containing the primary key value for this object.

◆ getPrimaryKeyField() [2/2]

const DataExecution::DataObject & getPrimaryKeyField ( ) const
Returns
The data object containing the primary key value for this object. This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

◆ getPrimaryKeyFieldName()

QString getPrimaryKeyFieldName ( ) const
Returns
The primary key field name associated with this object. Corresponds to the primary key field of the underlying bound table or view.
See also
getPrimaryKeyFieldNameAliased()
getPrimaryKeyField()

◆ getPrimaryKeyFieldNameAliased()

QString getPrimaryKeyFieldNameAliased ( ) const
Returns
The aliased version of the primary key field name.

All object fields, when used in a query, must be appropriately aliased so as to avoid naming conflicts with other object types. For example, if two objects were to have the same field, 'Name', it would be impossible to distinguish which field is which. For this reason, we alias each field so that it is unique in any underlying Sql queries.

See also
getPrimaryKeyFieldName()
getPrimaryKeyField()

◆ getRelationBindings()

SqlBindingRelationMap getRelationBindings ( const QStringList relationNames = QStringList(),
bool  recursive = false 
) const
Parameters
relationNamesThe list of relation bindings to retrieve. Each binding has a unique name associated with it. If the name in the list does not match a valid relationship name, it will be ignored.
recursiveWhether or not to recursively retrieve bindings from child objects to their own child objects.
Returns
A mapping of relation name to SqlBindingRelation objects, each representing one of this objects bindings to one or more other objects.

◆ getRelationFieldNames()

QStringList getRelationFieldNames ( bool  recursive) const
Returns

◆ getSqlValidCompositePrimaryKeyFieldNames()

QStringList getSqlValidCompositePrimaryKeyFieldNames ( ) const
Returns
Returns a QStringList of the composite primary key field names, where each name has been formatted so that it's ready to use directly in an SQL query. If the object does not have a composite primary key, an empty QStringList is returned.

SQL-valid field names take the form:

tableName.fieldName fieldNameAlias
See also
hasCompositePrimaryKey()
getCompositePrimaryKeyFieldNames()
getCompositePrimaryKeyFieldNamesAliased()

◆ getSqlValidFieldList()

QStringList getSqlValidFieldList ( ) const
Returns
A list of all the field names used by this bound object, not including relation names. The field names are formatted so that they can be used directly in an SQL query.

Sql-valid field names take the format: "<tableName>.<fieldName> <fieldAlias>"

Note
Relation field names, i.e. those that refer to another object deriving from SqlBoundObjectGroup and are included in a QSqlBoundRelation, are not included in this list because including them directly in SQL is not possible. Instead, any query being constructed must use the SqlBindingRelation::getJoinStatement() function to obtain the relation information.
See also
getNonRelationFieldNames()
getNonRelationFieldAliases()

◆ getUpdateQuery()

virtual QSqlQuery getUpdateQuery ( const SqlDataModel model,
const QStringList relations,
const QString &  foreignKeyName = QString(),
const QVariant &  foreignKeyValue = QVariant() 
) const
protectedpure virtual
Parameters
modelThe SqlDataModel responsible for the update operation.
relationsA list of relations to follow when generating the update.
foreignKeyName(optional) The name of a foreign key field attached to the table that this object is bound to. Important for updating objects with bi-directional relations.
foreignKeyValueThe value to store in the field named foreignKeyName when updating this object.
Returns
A QSqlQuery that can be executed to update this object in the database associated with model.

Implemented in TypedSqlBoundObjectGroup< Derived, PrimaryKeyType >, and InvalidSqlBoundObjectGroup.

◆ hasCompositePrimaryKey()

bool hasCompositePrimaryKey ( ) const
Returns
true if this object has a composite primary key (i.e. a primary key comprised of multiple fields). Returns false if the object has a regular, single field primary key.
See also
getCompositePrimaryKeyFieldNames()
getCompositePrimaryKeyFieldNamesAliased()
getSqlValidCompositePrimaryKeyFieldNames()

◆ isPersistent()

bool isPersistent ( ) const
Returns
Whether or not this object is persistent.

A persistent object is one that exists in the underlying SqlDataModel that this object is associated with. Objects that have been retrieved from an SqlDataModel via the use of the SqlDataModel::fetch() or written to an SqlDataModel via the SqlDataModel::save() functions will be persistent.

Objects that have been created locally but not retrieved via a fetch() call, and that have not yet been saved to the data model will not be marked as persistent.

See also
setPersistent()

◆ isPrimaryKeyField()

bool isPrimaryKeyField ( const DataExecution::DataObject obj) const
Parameters
objA child data object of this object group.
Returns
true if the object is the primary key field of this object group, false if it is not the primary key field, or is not a child of this object at all.

◆ isRelationField()

bool isRelationField ( const QString &  fieldName) const
Parameters
fieldNameThe name of the field to evaluate whether or not it is a relation field (i.e. a field that is bound to a related object), or a regular field bound directly to a database field.
Returns
true if fieldName corresponds to a relation field, false if it is a regular field.

◆ operator=()

SqlBoundObjectGroup & operator= ( const SqlBoundObjectGroup rhs)
protected
Parameters
rhsThe other SqlBoundObjectGroup to assign to this one.
Returns
a reference to this object so that multiple assignments can be chained.

Assigns the object rhs to this object, causing the two objects to refer to the same underlying database record. This means that the members of the two objects will refer directly to the same data, and so making changes to the members of one object will also be reflected in the contents of the other object.

To separate the link between the two objects (i.e. to indicate that they refer to two separate, but identical records), use the detach() function.

◆ operator==()

bool operator== ( const SqlBoundObjectGroup rhs) const
protected
Parameters
rhsThe other SqlBoundObjectGroup to compare to.
Returns
Always returns false. We do not support generic comparison of SqlBoundObjectGroups of different types. Calling code should always compare derived class objects directly.

◆ setPersistent()

void setPersistent ( bool  b)
Parameters
bWhether or not to mark this object as persistent.
See also
isPersistent()

◆ setPrimaryKeyField()

bool setPrimaryKeyField ( const DataExecution::DataObject obj,
bool  autoIncrement 
)
protected
Parameters
objReference to a bound object (already registered using bindField) that is going to contain the primary key data of the object.
autoIncrementWhether or not the primary key field is auto-incremented or must be manually set by calling code.
Returns
true if the field was able to be set successfully, false if it is not a valid child object (i.e. it has not been bound to this object by calling bindField()), or the object's field name is invalid (e.g. an empty string).