company logo

ORMapper - Storing ODABA data in relational databases

ODABA supports storing data in several relational databases. This is not the most efficient way of accessing data stored in ODABA, but it provides additional data access by well known SQL tools. Thus, running ODABA based on an SQL database might increase acceptance by customers.

The following SQL databases have been chosen for ODABA support:

  • ORACLE
  • Microsoft SQL Server
  • My SQL

This list might be expanded when ever required.

In order to create SQL table definitions for a project or module, one may call an OSI expression as described below or use the ODE ClassEditor (see Class Editor/Generate external resources/SQL Definitions ).

RDB access architecture

When running ODABA with a relational database, instances data is stored in relational tables. Optional, the administrator may decide whether to maintain m:n relationships in the RDBM or not. Thus, one may store data tables, only or data tables plus relationship tables.

In order to obtain extended ODABA features as collection events, extended instance and collection information etc. an additional database (Object Manager) is required.

Extended information as update counts for instances or collections, weak-typed or untyped collections or __IDENTITY /type mapping could hardly be handled in an relational database. Thus, an Object Manager maintains collections (relationships and references), but also update counts, locking and persistent write protection.

All services as transaction management, locking or workspace features are managed by ODABA, since SQL databases do not provide sufficient support e.g. for locking the children collection of a person. Moreover, ODABA cares about extended deletion features, maintaining inverse references and other specific object-oriented database features.

OR mapping rules

Since the information content of a relational database is a subset of the information, that can be stored in an object oriented database, mapping rules can be defined for the "relational data" in the object-oriented database. The requirement for mapping rules results from the fact, that relational databases do not support complex attributes, which will be resolved to property path (address.city). Moreover, relationships are transferred to mapping tables (m:n relationships).

Specific attributes result from the fact, that collections in ODABA (e.g. the children of a person) are considered as objects. In order to benefit from this feature also when running the ODABA application in a relational database, collection attributes are created, which refer to the local unique identifier for the collections (LOID).

In order to define relational tables, ODABA creates tables and attributes according to the rules described below. First, ODABA type and property names are converted into ODABA table and attribute names. The ODABA table or attribute name is always a name constructed from ODABA type and property names. ODABA table and attribute names created might be truncated later on, when exceeding the name size allowed by the target system.

ODABA table names are the corresponding table names for ODABA data types. ODABA table names for M:N relationships are composed from several property and type names. Table names might be converted in to target system table names (e.g. Oracle table names), when exceeding the maximum length.

ODABA attribute names are property names. Property names in complex attributes are preceded by the property name for the attribute. Thus, ODABA attribute names may contain a number of ODABA property names separated by dots.

Depending on the features of the target database system, comments are stored to the table and column definitions and/or written to the table definition file.

The examples are generated from the schema definition below describing an update register for documents and presentations.

//******************************** Schema *****************************************************

// type     example

// date     10-03-20 17:47:25.82

// dbsource  - ODABA Version 10.0

//*************************************************************************************

UPDATE SCHEMA example

{

//******************************** Enumeration *****************************************************

// type     UpdateTypes

// date     10-03-20 17:47:25.95

// dbsource  - ODABA Version 10.0

//*************************************************************************************

UPDATE ENUM UpdateTypes

{

   change                                             = 3,

   create                                             = 2,

   delete                                             = 1,

   other                                              = 0,

};

//******************************** Class *****************************************************

// type     Document

// date     10-03-20 17:47:26.10

// dbsource  - ODABA Version 10.0

//*************************************************************************************

NEW CLASS Document PERSISTENT VERSION=0 TYPE_ID=1756  GUID

       :   PUBLIC UpdateObject GUID OWNER updateObject

               VERSION=0

               ORDERED_BY ( ik UNIQUE )

(

  KEY { IDENT_KEY ik( id_number ); };

  ALIGNMENT = 0;

)

{

};

//******************************** Class *****************************************************

// type     Notice

// date     10-03-20 17:47:27.06

// dbsource  - ODABA Version 10.0

//*************************************************************************************

NEW CLASS Notice PERSISTENT VERSION=0 TYPE_ID=1753  GUID

(

  KEY { IDENT_KEY ik( id_number ); };

  ALIGNMENT = 0;

)

{

   ATTRIBUTE {

           PROTECTED INT(10,0) id_number

               VERSION=0;

   };

   REFERENCE {

           PROTECTED MEMO(4000) OWNER text [1]

               VERSION=0;

   };

};

//******************************** Class *****************************************************

// type     Presentation

// date     10-03-20 17:47:27.18

// dbsource  - ODABA Version 10.0

//*************************************************************************************

NEW CLASS Presentation PERSISTENT VERSION=0 TYPE_ID=1757  GUID

       :   PUBLIC UpdateObject GUID OWNER updateObject

               VERSION=0

               ORDERED_BY ( ik UNIQUE )

(

  KEY { IDENT_KEY ik( id_number ); };

  ALIGNMENT = 0;

)

{

};

//******************************** Class *****************************************************

// type     Update

// date     10-03-20 17:47:27.21

// dbsource  - ODABA Version 10.0

//*************************************************************************************

NEW CLASS Update PERSISTENT VERSION=0 TYPE_ID=1754  GUID

       :   PUBLIC Notice GUID UPDATE Notice

               VERSION=0

               BASED_ON   Notice

(

  KEY { IDENT_KEY ik( id_number ); };

  ALIGNMENT = 0;

)

{

   ATTRIBUTE {

           PROTECTED STRING(100) title

               VERSION=0;

           PROTECTED UpdateTypes update_types

               VERSION=0;

   };

   REFERENCE {

           PROTECTED Notice UPDATE OWNER notices

               VERSION=0;

   };

   RELATIONSHIP {

           PROTECTED Update UPDATE related_updates

               VERSION=0

               INVERSE    referenced_in

               BASED_ON   Update

               ORDERED_BY ( ik UNIQUE );

           PROTECTED Update UPDATE SECONDARY referenced_in

               VERSION=0

               INVERSE    related_updates

               BASED_ON   Update

               ORDERED_BY ( ik UNIQUE );

           PROTECTED UpdateObject UPDATE WEAK_TYPED SECONDARY object [1]

               VERSION=0

               INVERSE    updates

               BASED_ON   *

               ORDERED_BY ( ik UNIQUE );

   };

};

//******************************** Class *****************************************************

// type     UpdateObject

// date     10-03-20 17:47:27.35

// dbsource  - ODABA Version 10.0

//*************************************************************************************

NEW CLASS UpdateObject PERSISTENT VERSION=0 TYPE_ID=1755  GUID    

(

  KEY { IDENT_KEY ik( id_number ); };

  ALIGNMENT = 0;

)

{

   ATTRIBUTE {

           PROTECTED INT(10,0) id_number

               VERSION=0;

   };

   RELATIONSHIP {

           PROTECTED Update UPDATE updates

               VERSION=0

               INVERSE    object

               BASED_ON   Update;

   };

};

UPDATE EXTENT Document UPDATE MULTIPLE_KEY OWNER Document

               VERSION=0

               ORDERED_BY ( ik UNIQUE LARGE );

UPDATE EXTENT Notice UPDATE MULTIPLE_KEY OWNER Notice

               VERSION=0

               ORDERED_BY ( ik UNIQUE LARGE );

UPDATE EXTENT Presentation UPDATE MULTIPLE_KEY OWNER Presentation

               VERSION=0

               ORDERED_BY ( ik UNIQUE LARGE );

UPDATE EXTENT Update UPDATE MULTIPLE_KEY OWNER Update

               VERSION=0

               ORDERED_BY ( ik UNIQUE LARGE );

};

Memo and blob properties

Two tables are created in order to store the MEMO and BLOB type properties. Each row in the table contains a local unique identifier (LOID) for the MEMO or BLOB property and the CLOB or BLOB field in order to store the large character or binary object.

References to MEMO or BLOB properties are stored as links to the SYS__MEMO or SYS__BLOB table. Within the current table, a link attribute to the MEMO or BLOB table is defined with the odaba property name.

-- oracle

  CREATE TABLE "SYS__MEMO"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL PRIMARY KEY USING INDEX TABLESPACE "example_INDEX",

    "SYS__ENTRY"    CLOB

  )  LOB ("SYS__ENTRY") STORE AS ( STORAGE ( INITIAL 4M) NOCACHE NOLOGGING );

  CREATE TABLE "SYS__BLOB"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL PRIMARY KEY USING INDEX TABLESPACE "example_INDEX",

    "SYS__ENTRY"    BLOB

  )  LOB ("SYS__ENTRY") STORE AS ( STORAGE ( INITIAL 4M) NOCACHE NOLOGGING );

-- ...

  ALTER TABLE "Notice" ADD ( "text" NUMERIC (20,0) REFERENCES "SYS__MEMO" );

Enumerations

For each enumeration a table with the enumeration name will be created. Enumerator values (code and title) are stored to the table. Hierarchical enumerations are stored as flat ones. Details as constraint, enumerator type or detailed description are not stored to the relational database, since those information is still available via the ODABA dictionary.

Enumerator names and values are used as being defined in ODABA.

-- oracle

  CREATE TABLE "UpdateTypes"

  (

    "code"     NUMERIC(5,0) NOT NULL ,

    "name"     VARCHAR(40) ,

    PRIMARY KEY ("code") USING INDEX TABLESPACE "example_INDEX"

  );

INSERT INTO "UpdateTypes" VALUES ('1', 'delete');

INSERT INTO "UpdateTypes" VALUES ('2', 'create');

INSERT INTO "UpdateTypes" VALUES ('3', 'change');

INSERT INTO "UpdateTypes" VALUES ('0', 'other');

Complex data typed

Instance data is stored in tables having the same name as the complex data type defined in the ODABA object model. All tables get an additional property SYS__LOID , which holds the local object identity for each instance. All relational tables are indexed by SYS__LOID . For each complex ODABA data type a table will be created.

-- oracle

  CREATE TABLE "Update"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL,

    PRIMARY KEY ("SYS__LOID") USING INDEX TABLESPACE "example_INDEX"

  );

Extents

Being a member of an extent is an additional information, which cannot be directly stored in the relational database. Thus, each extent creates an additional reference attribute in the data type referenced in the extent (owner reference, since extents are usually the owner of the instances).

The name for the owner reference is the is the extent name succeeded by two underscores ( Notice __ ). Thus, it becomes possible to distinguish between notices stored in the Notice extent and those stored locally for an Update instance.

-- oracle

  ALTER TABLE "Notice" ADD ( "Notice__" NUMERIC(20,0) );

Inheritance

When a type inherits exclusive from its base type, properties defined in the base type(s) are considered as properties of the type. Thus, Attributes of exclusive inherited base types might become attributes in any number of tables.

When a data type inherits shared from its base structure, attributes are stored in a separate table for the base type using the same names as in the data model definition. An attribute with the name of the base type member is added to the table, which refers to the base type table entry LOID ( SYS__LOID ) value for the base instance in the referenced table.

-- oracle, shared base type

  ALTER TABLE "Update" ADD ( "Notice" NUMERIC(20,0) REFERENCES "Notice" );

Attributes

Attributes are defined as table columns using the attribute name. Complex attributes are provided as resolved attribute paths including dots, which are part of the attribute path ( address.city ). Such names, usually require name quotes, which depend on target system. When referring to attribute names in exclusive base types, names are not prefixed.

When an attribute defines a fixed array, a column will be created for each array element. Each array element except the first will be extended by the element position in the array (e.g. name_1).

ODABA data types are converted to appropriate types in the target system. Generated column types may differ for different target systems. Enumeration values are converted into link columns, e.g. columns referring to the enumeration table.

// oracle

  ALTER TABLE "Update" ADD ( "title" VARCHAR(100) );

  ALTER TABLE "Update" ADD ( "update_type" NUMERIC(5,0) REFERENCES "UpdateTypes" );

Collections and references

Collections and singular references allowing asynchroneously updates create a collection identity (LOID) in order to identify the collection object. The collection objects play an important role, when updating collections. Essential parts of the application logic interface (ALI) are based on collection events. For using this features, collection attributes are stored in table instances as well, even though the are not of interest for relational queries.

Collection attributes will be created for all references/relationships, which are multiple or weak-typed or can be updated asynchronously.

Collection attributes are stored with their property (reference or relationship) name preceded by two underscores ( __related_updates ).

-- oracle

  ALTER TABLE "Update" ADD ( "__related_updates" NUMERIC(20,0) );

  CREATE TABLE "Update__related_updates"

  (

    "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Update",

    "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Update",

    PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

  );

References

References (and owning relationships) define a 1:N relationship and create an owner attribute in the table defined by the referenced type. The column name is constructed from the property (reference or relationship) name and the current type name (e.g. notices__Update ).

-- oracle

  ALTER TABLE "Notice" ADD ( "notices__Update" NUMERIC(20,0) REFERENCES "UpdateRegister" );

Notes:

Usually, owning relationships are defined as primary relationships. When this is not the case, the inverse relationship will create a M:N table, in addition. This is not a problem, but leeds to (unnecessary) redundancy.

Relationships

For not owning relationships, a mapping table for related instances will be created, when the relationship is primary. The table name will be constructed from the object name and the relationship name (e.g. Update__related_updates ). The two columns contain the local unique identifiers for the rows in the target tables as being referenced in the column statement.

When exceeding the naming limits for the target system, a unique table name will be created.

-- oracle

  CREATE TABLE "Update__related_updates"

  (

    "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Update",

    "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Update",

    PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

  );

Weak-typed collections

Weak typed collections (references or relationships) create mapping tables for each data type which inherits directly or indirectly exclusive from the referenced type. Mapping tables are created for references or primary relationships, only. The table names for weak-typed collection are constructed from the current table name, the property name and the target table name separated by double underscore ( Update__object__Document ).

-- oracle, simulated by setting object in Update to primary

  CREATE TABLE "Update__object"

  (

    "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Update",

    "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "UpdateObject",

    PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

  );

  CREATE TABLE "Update__object__Document"

  (

    "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Update",

    "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Document",

    PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

  );

  CREATE TABLE "Update__object__Presentation"

  (

    "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Update",

    "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Presentation",

    PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

  );

Generic attributes

Generic attributes are considered as multiple references and will create a collection attribute in the current table and an owner attribute in the referenced type for the generic attribute (see References).

ODL example
SQL example (oracle)

Below, you will find the complete set of table definitions created from the example (update register) described in the ODL example.

--

-- SQL Schema : ODABA Dictionary for example

-- Target DB  : Oracle

-- Version    : 1.0

-- Date       : 10-03-20 Time: 19:00:55.76

--

  CREATE TABLE "SYS__MEMO"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL PRIMARY KEY USING INDEX TABLESPACE "example_INDEX",

    "SYS__ENTRY"    CLOB

  )  LOB ("SYS__ENTRY") STORE AS ( STORAGE ( INITIAL 4M) NOCACHE NOLOGGING );

  CREATE TABLE "SYS__BLOB"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL PRIMARY KEY USING INDEX TABLESPACE "example_INDEX",

    "SYS__ENTRY"    BLOB

  )  LOB ("SYS__ENTRY") STORE AS ( STORAGE ( INITIAL 4M) NOCACHE NOLOGGING );

  CREATE TABLE "UpdateTypes"

  (

    "code"     NUMERIC(5,0) NOT NULL ,

    "name"     VARCHAR(40) ,

    PRIMARY KEY ("code") USING INDEX TABLESPACE "example_INDEX"

  );

INSERT INTO "UpdateTypes" VALUES ('3', 'change');

INSERT INTO "UpdateTypes" VALUES ('2', 'create');

INSERT INTO "UpdateTypes" VALUES ('1', 'delete');

INSERT INTO "UpdateTypes" VALUES ('0', 'other');

  CREATE TABLE "Document"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL,

    PRIMARY KEY ("SYS__LOID") USING INDEX TABLESPACE "example_INDEX"

  );

  CREATE TABLE "Notice"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL,

    PRIMARY KEY ("SYS__LOID") USING INDEX TABLESPACE "example_INDEX"

  );

  CREATE TABLE "Presentation"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL,

    PRIMARY KEY ("SYS__LOID") USING INDEX TABLESPACE "example_INDEX"

  );

  CREATE TABLE "Update"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL,

    PRIMARY KEY ("SYS__LOID") USING INDEX TABLESPACE "example_INDEX"

  );

  CREATE TABLE "UpdateObject"

  (

    "SYS__LOID"     NUMERIC(20,0) NOT NULL,

    PRIMARY KEY ("SYS__LOID") USING INDEX TABLESPACE "example_INDEX"

  );

-- Extent references

    ALTER TABLE "Document" ADD ( "Document__" NUMERIC(20,0) );

    COMMENT ON COLUMN "Document"."Document__" IS 'Owner: Document';

    ALTER TABLE "Notice" ADD ( "Notice__" NUMERIC(20,0) );

    COMMENT ON COLUMN "Notice"."Notice__" IS 'Owner: Notice';

    ALTER TABLE "Presentation" ADD ( "Presentation__" NUMERIC(20,0) );

    COMMENT ON COLUMN "Presentation"."Presentation__" IS 'Owner: Presentation';

    ALTER TABLE "Update" ADD ( "Update__" NUMERIC(20,0) );

    COMMENT ON COLUMN "Update"."Update__" IS 'Owner: Update';

-- Structure Definition Document

    ALTER TABLE "Document" ADD ( "id_number" NUMERIC(10,0) );

    COMMENT ON COLUMN "Document"."id_number" IS 'Attribute: Document.updateObject.id_number';

    ALTER TABLE "Document" ADD ( "__updates" NUMERIC(20,0) );

    COMMENT ON COLUMN "Document"."__updates" IS 'Collection: Document.updateObject.updates';

        CREATE TABLE "Document__updates"

        (

          "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Document",

          "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Update",

          PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

        );

-- Structure Definition Notice

    ALTER TABLE "Notice" ADD ( "id_number" NUMERIC(10,0) );

    COMMENT ON COLUMN "Notice"."id_number" IS 'Attribute: Notice.id_number';

    ALTER TABLE "Notice" ADD ( "text" NUMERIC (20,0) REFERENCES "SYS__MEMO" );

    COMMENT ON COLUMN "Notice"."text" IS 'Reference: Notice.text';

-- Structure Definition Presentation

    ALTER TABLE "Presentation" ADD ( "id_number" NUMERIC(10,0) );

    COMMENT ON COLUMN "Presentation"."id_number" IS 'Attribute: Presentation.updateObject.id_number';

    ALTER TABLE "Presentation" ADD ( "__updates" NUMERIC(20,0) );

    COMMENT ON COLUMN "Presentation"."__updates" IS 'Collection: Presentation.updateObject.updates';

        CREATE TABLE "Presentation__updates"

        (

          "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Presentation",

          "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Update",

          PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

        );

-- Structure Definition Update

    ALTER TABLE "Update" ADD ( "Notice" NUMERIC(20,0) REFERENCES "Notice" );

    COMMENT ON COLUMN "Update"."Notice" IS 'Reference: Update.Notice';

    ALTER TABLE "Update" ADD ( "title" VARCHAR(101) );

    COMMENT ON COLUMN "Update"."title" IS 'Attribute: Update.title';

    ALTER TABLE "Update" ADD ( "update_types" NUMERIC(5,0) REFERENCES "UpdateTypes" );

    COMMENT ON COLUMN "Update"."update_types" IS 'Attribute: Update.update_types';

    ALTER TABLE "Update" ADD ( "__notices" NUMERIC(20,0) );

    COMMENT ON COLUMN "Update"."__notices" IS 'Collection: Update.notices';

    ALTER TABLE "Notice" ADD ( "notices__Update" NUMERIC(20,0) REFERENCES "Update" );

    COMMENT ON COLUMN "Notice"."notices__Update" IS 'Owner: notices';

    ALTER TABLE "Update" ADD ( "__related_updates" NUMERIC(20,0) );

    COMMENT ON COLUMN "Update"."__related_updates" IS 'Collection: Update.related_updates';

        CREATE TABLE "Update__related_updates"

        (

          "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "Update",

          "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Update",

          PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

        );

    ALTER TABLE "Update" ADD ( "__referenced_in" NUMERIC(20,0) );

    COMMENT ON COLUMN "Update"."__referenced_in" IS 'Collection: Update.referenced_in';

    ALTER TABLE "Update" ADD ( "__object" NUMERIC(20,0) );

    COMMENT ON COLUMN "Update"."__object" IS 'Collection: Update.object';

-- Structure Definition UpdateObject

    ALTER TABLE "UpdateObject" ADD ( "id_number" NUMERIC(10,0) );

    COMMENT ON COLUMN "UpdateObject"."id_number" IS 'Attribute: UpdateObject.id_number';

    ALTER TABLE "UpdateObject" ADD ( "__updates" NUMERIC(20,0) );

    COMMENT ON COLUMN "UpdateObject"."__updates" IS 'Collection: UpdateObject.updates';

        CREATE TABLE "UpdateObject__updates"

        (

          "SYS__LOID" NUMERIC(20,0) NOT NULL REFERENCES "UpdateObject",

          "SYS__REF"  NUMERIC(20,0) NOT NULL REFERENCES "Update",

          PRIMARY KEY ("SYS__LOID","SYS__REF") USING INDEX TABLESPACE "example_INDEX"

        );

Naming

As long as possible, the target system uses the ODABA names.

Names supported in relational databases differ. Thus, Oracle supports not more than 30 characters for table and column names, while MS SQL Server allows table and column names up to 128 characters. Since table names may consists of three ODABA names plus underline characters and column names do not have any limit, names have to be truncated in order to provide unique names.

Moreover, name mapping is required later on for data access and also for documenting the mapping between ODABA and the target SQL database. Thus, when creating table definitions for a selected target system, a name translation table will be created, which provides the mapping between table and column names constructed by ODABA and table and column names in the target system. Translation tables are stored in the dictionary in following collections:

  • SDB_SQLTarget('Oracle').names (Oracle mapping)
  • SDB_SQLTarget('MSSQL').names (MS SQL Server mapping)
  • SDB_SQLTarget('MySQL').names (MySQL mapping)

Name mappings can be viewed also in the ClassEditor Objects/SQL Targets .

Limitations

Running ODABA with a relational database underneath causes some restrictions. The first and most important one is, that the relational data storage might be accessed by SQL tools in order to perform queries, but not in order to update the database. All update operations must pass through the object relation mapper (ORM). Otherwise, the ORM database might become inconsistent. In detail, following restrictions have to be taken into account:

  • Since relational databases usually do not support namespaces for tables, data model definitions running with relational data storage must not define persistent namespaces. Instead, type names should be prefixed or marked in any other way. In the model definition, one may define object types in modules or namespaces, but those must not be marked as active namespaces, i.e. type names must be unique within the dictionary.
  • In order to guarantee proper maintenance of inverse relationships, ODABA supports update-able relationships. In a relational database, update-able relationships behave similar as many to many relations. This means that queries against the relational database must include an additional join operation when referring to singular update-able links.
  • ODABA supports VOID type collections, i.e. collections, which may contain instances of any type. Theoretically, void collections could be supported, but this would require creating link tables between the type defining the VOID collection and all other defined types. This seems not to make much sense and has not been implemented. We suggest using weak-typed collections, instead.
  • Property names in exclusive base types must be unique in order to avoid naming conflicts.
  • Names of complex attributes are resolved. In case of deep nesting, this might exceed name length limits in the target system. The mapping tools care about creating proper names, but those might be difficult to read. Hence, attribute nesting and name length should be selected in a way that meets the target system requirements.
  • Instance versioning is not yet supported for relational storage.
  • Extension properties are not yet available.
  • Many databases do not support different text encoding methods for text fields, i.e. one should use STRING (uses default encoding) always in order to avoid conflicts.

Other limitations are of minor importance. There are several features that require specific ODABA storage. Thus, when using workspaces, all workspace data is stored in ODABA databases and is accessible via SQL only, when the workspace data has been consolidated to the root base.

Similar, long external transactions require an external ODABA transaction database and data becomes available only after committing the external transaction.

SYS__LOID values (identities) are the base for all links and instance identification and must not change after being created.