From 762448ca92b948c1701d07a3403e93f1c27c19bd Mon Sep 17 00:00:00 2001
From: Boris Kolpackov
An object is an independent entity. It can be stored, updated, - and deleted in the database independent of other objects or values. + and deleted in the database independent of other objects. An object has an identifier, called object id, that is - unique among all instances of an object type within a database. - An object consists of data members which are either values or - references to other objects. In contrast, a value can only be - stored in the database as part of an object and doesn't have - its own unique identifier.
+ unique among all instances of an object type within a database. In + contrast, a value can only be stored in the database as part of an + object and doesn't have its own unique identifier. + +An object consists of data members which are either values, pointers + to other objects (Chapter Y, "Relationships"), or + containers of values or pointers to other objects (Chapter + X, "Containers"). Pointers to other objects and containers can + be viewed as special kinds of values since they also can only + be stored in the database as part of an object.
An object type is a C++ class. Because of this one-to-one relationship, we will use terms object type @@ -1566,7 +1571,7 @@ Hello, Joe! viewed (and mapped) as both simple and composite by different applications.
-Seeing how all these concepts map to the relational model +
Understanding how all these concepts map to the relational model will hopefully make these distinctions clearer. In a relational database an object type is mapped to a table and a value type is mapped to one or more columns. A simple value type is mapped @@ -1600,11 +1605,11 @@ Hello, Joe! example:
- #pragma db object - class person - { - ... - }; +#pragma db object +class person +{ + ... +};
The other pragma that we often use is db id
@@ -1612,14 +1617,15 @@ Hello, Joe!
example:
- #pragma db object - class person - { +#pragma db object +class person +{ + ... - private: - #pragma db id - unsigned long id_; - }; +private: + #pragma db id + unsigned long id_; +};
These two pragmas are the minimum required to declare a @@ -1634,10 +1640,26 @@ Hello, Joe! how to convert between the two. On the other hand, if a simple value is unknown to the ODB compiler then you will need to provide the mapping to the database system type and, possibly, the code to - convert between the two. For more information on this refer to - Section 5.3, "Value Type Pragmas". Composite - value types are not yet supported by ODB and we will not discuss - them further in this revision of the manual.
+ convert between the two. For more information on how to achieve + this refer to thedb type
pragma (Section
+ 5.3.1, "type
"). Similar to object types, composite
+ value types have to be explicitly declared as persistent using the
+ db value
pragma, for example:
+
+ +#pragma db value +class name +{ + ... + +private: + std::string first_; + std::string last_; +}; ++ +
Composite values are discussed in greater detail in Chapter + Z, "Composite Value Types".
Normally, you would use object types to model real-world entities, things that have their own identity. For example, in the @@ -1698,15 +1720,15 @@ Hello, Joe! database system:
- #include <odb/database.hxx> - #include <odb/mysql/database.hxx> +#include <odb/database.hxx> +#include <odb/mysql/database.hxx> - auto_ptr<odb::database> db ( - new odb::mysql::database ( - "test_user" // database login name - "test_password" // database password - "test_database" // database name - )); +auto_ptr<odb::database> db ( + new odb::mysql::database ( + "test_user" // database login name + "test_password" // database password + "test_database" // database name + ));
The odb::database
class is a common interface for
@@ -2324,11 +2346,11 @@ private:
in detail in the following sections.
Containers in ODB can contain simple value types, composite value - types (see @@), and object pointers (see @@). Containers of - containers are not supported. A key in map and multimap - containers can be a simple or composite value type but not - an object pointer. An index in the ordered container should - be a simple integer type.
+ types (see @@), and pointers to objects (see @@). Containers of + containers, either directly or indirectly via a composite value + type, are not allowed. A key in map and multimap containers can + be a simple or composite value type but not a pointer to an object. + An index in the ordered container should be a simple integer type.The value type in the ordered, set, and map containers as well as the key type in the map containers should be default-constructible. @@ -3626,6 +3648,322 @@ t.commit (); +
Composite value type is a class
or struct
+ type that is mapped to more than one database column. To declare
+ a composite value type we use the db value
pragma,
+ for example:
+#pragma db value +class basic_name +{ + ... + + std::string first_; + std::string last_; +}; ++ +
A composite value type does not have to define a default constructor,
+ unless it is used as an element of a container, in which case the
+ default constructor can be made private. If a composite value type
+ has private or protected non-transient data members or if its
+ default constructor is not public and the value type is used as
+ an element in a container, then the odb::access
class
+ should be declared a friend of this value type. For example:
+#pragma db value +class basic_name +{ +public: + basic_name (const std::string& first, const std::string& last); + + ... + +private: + friend class odb::access; + + basic_name () {} // Needed for storing basic_name in containers. + + std::string first_; + std::string last_; +}; ++ +
The complete versions of the above code fragment as well as other code
+ samples presented in this chapter can found in the composite
+ example in the odb-examples
package.
The members of a composite value can be other value types (either + simple or composite), containers (@@ ref), and object pointers (@@ ref). + Similarly, a composite value type can be used in object members, + as an element in a container, and as a base for another composite + value type. In particular, composite value types can be used as + element types in set containers (@@ ref) and as key types in map + containers (@@ ref). A composite value type that is used as an + element of a container cannot contain other containers since + containers of containers are not allowed. The following example + illustrates some of the possible use cases:
+ ++#pragma db value +class basic_name +{ + ... + + std::string first_; + std::string last_; +}; + +typedef std::vector<basic_name> basic_names; + +#pragma db value +class name_extras +{ + ... + + std::string nickname_; + basic_names aliases_; +}; + +#pragma db value +class name: public basic_name +{ + ... + + std::string title_; + name_extras extras_; +}; + +#pragma db object +class person +{ + ... + + #pragma db id auto + unsigned long id_; + + name name_; +}; ++ +
We can also use the data members from the composite value types
+ in database queries (Chapter 4, "Querying the
+ Database"). For each composite value in a persistent class,
+ the query class defines a nested scope containing members corresponding
+ to the data members in the value type. For example, the
+ query class for the person
object presented above
+ contains the name
scope (derived from the name_
+ data member) which in turn contains the extras
member
+ (derived from the name::extras_
data member of the
+ composite value type). The process continues reqursively for nested
+ composite value types and, as a result, we can use the
+ query::name::extras::nickname
expression while querying
+ the database for the person
objects. For example:
+typedef odb::query<person> query; +typedef odb::result<person> result; + +transaction t (db->begin ()); + +result r (db->query<person> ( + query::name::extras::nickname == "Squeaky")); + +... + +t.commit (); ++ +
Customizing a column name for a data member of a simple value
+ type is straightforward: we simply specify the desired name with
+ the db column
pragma (@@ ref). For composite value
+ types things are slightly more complicated since it is mapped to
+ multiple columns. Consider the following example:
+#pragma db value +class name +{ + ... + + std::string first_; + std::string last_; +}; + +#pragma db object +class person +{ + ... + + #pragma db id auto + unsigned long id_; + + name name_; +}; ++ +
The column names for the first_
and last_
+ members are constructed by using the sanitized name of the
+ person::name_
member as a prefix and the names of the
+ members in the value type (first_
and last_
)
+ as suffixes. As a result, the database schema for the above classes
+ will look like this:
+CREATE TABLE person ( + id BIGINT UNSIGNED NOT NULL PRIMARY KEY, + name_first TEXT NOT NULL, + name_last TEXT NOT NULL); ++ +
We can customize both the prefix and the suffix using the
+ db column
pragma as shown in the following
+ example:
+#pragma db value +class name +{ + ... + + #pragma db column("first_name") + std::string first_; + + #pragma db column("last_name") + std::string last_; +}; + +#pragma db object +class person +{ + ... + + #pragma db column("person_") + name name_; +}; ++ +
The database schema changes as follows:
+ ++CREATE TABLE person ( + id BIGINT UNSIGNED NOT NULL PRIMARY KEY, + person_first_name TEXT NOT NULL, + person_last_name TEXT NOT NULL); ++ +
We can also make the column prefix empty, for example:
+ ++#pragma db object +class person +{ + ... + + #pragma db column("") + name name_; +}; ++ +
This will result in the following schema:
+ ++CREATE TABLE person ( + id BIGINT UNSIGNED NOT NULL PRIMARY KEY, + first_name TEXT NOT NULL, + last_name TEXT NOT NULL); ++ +
The same principal applies when a composite value type is used
+ as an element of a container, except that instead of
+ db column
either the db value_column
+ (@@ ref) or db key_column
(@@ ref) pragmas are used to
+ specify the column prefix.
When a composite value type contains a container, an extra table + is used to store the elements (@@ ref Chapter X, "Containers"). + The names of such tables are constructed in a way similar to the + column names, except that by default both the object name and the + member name are used as a prefix. For example:
+ ++#pragma db value +class name +{ + ... + + std::string first_; + std::string last_; + std::vector<std::string> nicknames_; +}; + +#pragma db object +class person +{ + ... + + name name_; +}; ++ +
The corresponding database schema will look like this:
+ ++CREATE TABLE `person_name_nicknames` ( + `object_id` BIGINT UNSIGNED NOT NULL, + `index` BIGINT UNSIGNED NOT NULL, + `value` TEXT NOT NULL) + +CREATE TABLE person ( + id BIGINT UNSIGNED NOT NULL PRIMARY KEY, + name_first TEXT NOT NULL, + name_last TEXT NOT NULL); ++ +
To customize the container table name we can use the
+ db table
(@@ ref) pragma, for example:
+#pragma db value +class name +{ + ... + + #pragma db table("nickname") + std::vector<std::string> nicknames_; +}; + +#pragma db object +class person +{ + ... + + #pragma db table("person_") + name name_; +}; ++ +
This will result in the following schema changes:
+ ++CREATE TABLE `person_nickname` ( + `object_id` BIGINT UNSIGNED NOT NULL, + `index` BIGINT UNSIGNED NOT NULL, + `value` TEXT NOT NULL) ++ +
Similar to columns, we can make the table prefix empty.
+ + + + +If you don't know the identifiers of the objects that you are looking @@ -5009,6 +5347,10 @@ private: }; +
For a member of a composite value type, the column
specifier
+ specifies the column name prefix. Refer to Section Z.1,
+ "Composite Value Column and Table Names" for details.
If the column name is not specified, it is derived from the member
name by removing the common member name decorations, such as leading
and trailing underscores, the m_
prefix, etc.
table
specifier, the container's
table name would have been person_nicknames
.
+ The table
specifier can also be used for members of
+ composite value types. In this case it specifies the table name
+ prefix for container members inside the composite value type. Refer
+ to Section Z.1, "Composite Value Column and Table
+ Names" for details.
index_type
The index_type
specifier specifies the native
--
cgit v1.1