From 2842ac773c779b6bd8298a34320076a8c5ca77ee Mon Sep 17 00:00:00 2001
From: Boris Kolpackov 3 Working with Persistent Objects
@@ -507,31 +508,32 @@ for consistency.
- 3.1 Concepts and Terminology
- 3.2 Object and View Pointers
- 3.3 Database
- 3.4 Transactions
- 3.5 Connections
- 3.6 Error Handling and Recovery
- 3.7 Making Objects Persistent
- 3.8 Loading Persistent Objects
- 3.9 Updating Persistent Objects
- 3.10 Deleting Persistent Objects
- 3.11 Executing Native SQL Statements
- 3.12 Tracing SQL Statement Execution
+ 3.13 ODB Exceptions
+ 3.2 Declaring Persistent Objects and Values
+ 3.3 Object and View Pointers
+ 3.4 Database
+ 3.5 Transactions
+ 3.6 Connections
+ 3.7 Error Handling and Recovery
+ 3.8 Making Objects Persistent
+ 3.9 Loading Persistent Objects
+ 3.10 Updating Persistent Objects
+ 3.11 Deleting Persistent Objects
+ 3.12 Executing Native SQL Statements
+ 3.13 Tracing SQL Statement Execution 3.14 ODB Exceptions 12.4.2 auto
12.4.3 type
- 12.4.4 id_type
- 12.4.5 null
/not_null
- 12.4.6 default
- 12.4.7 options
- 12.4.8 column
(object, composite value)
- 12.4.9 column
(view)
- 12.4.10 transient
- 12.4.11 readonly
- 12.4.12 inverse
- 12.4.13 version
- 12.4.14 index
- 12.4.15 unique
- 12.4.16 unordered
- 12.4.17 table
- 12.4.18 index_type
- 12.4.19 key_type
- 12.4.20 value_type
- 12.4.21 value_null
/value_not_null
- 12.4.22 id_options
- 12.4.23 index_options
- 12.4.24 key_options
- 12.4.25 value_options
- 12.4.26 id_column
- 12.4.27 index_column
- 12.4.28 key_column
+ 12.4.29 value_column
+ 12.4.5 get
/set
/access
+ 12.4.6 null
/not_null
+ 12.4.7 default
+ 12.4.8 options
+ 12.4.9 column
(object, composite value)
+ 12.4.10 column
(view)
+ 12.4.11 transient
+ 12.4.12 readonly
+ 12.4.13 inverse
+ 12.4.14 version
+ 12.4.15 index
+ 12.4.16 unique
+ 12.4.17 unordered
+ 12.4.18 table
+ 12.4.19 index_type
+ 12.4.20 key_type
+ 12.4.21 value_type
+ 12.4.22 value_null
/value_not_null
+ 12.4.23 id_options
+ 12.4.24 index_options
+ 12.4.25 key_options
+ 12.4.26 value_options
+ 12.4.27 id_column
+ 12.4.28 index_column
+ 12.4.29 key_column
@@ -654,6 +656,7 @@ for consistency.
12.4.30 value_column
16.5.5 Large FLOAT
and NUMBER
Types16.5.6 Timezones
+ 16.5.7 LONG
Types
@@ -678,6 +681,7 @@ for consistency.
16.5.8 LOB Types and By-Value Accessors/Modifiers 17.5.4 Multithreaded Windows Applications 17.5.5 Affected Row Count and DDL Statements
+ 17.5.6 Long Data and Automatically Assigned Object Ids
@@ -1125,17 +1129,11 @@ public:
const std::string& last,
unsigned short age);
- const std::string&
- first () const;
+ const std::string& first () const;
+ const std::string& last () const;
- const std::string&
- last () const;
-
- unsigned short
- age () const;
-
- void
- age (unsigned short);
+ unsigned short age () const;
+ void age (unsigned short);
private:
std::string first_;
@@ -1197,14 +1195,16 @@ private:
when instantiating an object from the persistent state. Just as we have
done for the 17.5.7 Long Data and By-Value Accessors/Modifiers person
class, you can make the default
constructor private or protected if you don't want to make it
- available to the users of your class.
With the fourth change we make the odb::access
class a
friend of our person
class. This is necessary to make
the default constructor and the data members accessible to the
- ODB support code. If your class has public default constructor and
- public data members, then the friend
declaration is
- unnecessary.
friend
declaration is unnecessary.
The final change adds a data member called id_
which
is preceded by another pragma. In ODB every persistent object normally
@@ -1228,20 +1228,41 @@ private:
in other countries), then we could use that as an id. Or, if
we stored an email associated with each person, then we could
have used that if each person is presumed to have a unique
- email address, for example:
As another example, consider the following alternative version
+ of the person
class. Here we use one of
+ the existing data members as id. Also the data members are kept
+ private and are instead accessed via public accessor and modifier
+ functions. Finally, the ODB pragmas are grouped together and are
+ placed after the class definition. They could have also been moved
+ into a separate header leaving the original class completely
+ unchanged (for more information on such a non-intrusive conversion
+ refer to Chapter 12, "ODB Pragma Language").
class person { - ... +public: + person (); - #pragma db id - std::string email_; + const std::string& email () const; + void email (const std::string&); - std::string first_; - std::string last_; + const std::string& get_name () const; + std::string& set_name (); + + unsigned short getAge () const; + void setAge (unsigned short); + +private: + std::string email_; + std::string name_; unsigned short age_; }; + +#pragma db object(person) +#pragma db member(person::email_) id
Now that we have the header file with the persistent class, let's @@ -1386,7 +1407,7 @@ mysql --user=odb_test --database=odb_test < person.sql only way to create a database schema in ODB. We can also embed the schema directly into our application or use custom schemas that were not generated by the ODB compiler. Refer to - Section 3.3, "Database" for details.
+ Section 3.4, "Database" for details.Once the database schema is ready, we run our application using the same login and database name:
@@ -1542,7 +1563,7 @@ main (int argc, char* argv[])The final bit of code in our example is the catch
block that handles the database exceptions. We do this by catching
- the base ODB exception (Section 3.13, "ODB
+ the base ODB exception (Section 3.14, "ODB
Exceptions") and printing the diagnostics.
Let's now compile (Section 2.3, "Compiling and
@@ -1616,7 +1637,7 @@ INSERT INTO `person` (`id`,`first`,`last`,`age`) VALUES (?,?,?,?)
Note that we see question marks instead of the actual values
because ODB uses prepared statements and sends the data to the
database in binary form. For more information on tracing, refer
- to Section 3.12, "Tracing SQL Statement Execution".
+ to Section 3.13, "Tracing SQL Statement Execution".
In the next section we will see how to access persistent objects
from our application.std::unique_ptr
from C++11 or shared_ptr
from TR1, C++11, or Boost. For more information
on the object lifetime management and the smart pointers that we
- can use for that, see Section 3.2, "Object
+ can use for that, see Section 3.3, "Object
and View Pointers".
With the instantiated object in hand we increment the age
@@ -2034,11 +2055,11 @@ max age: 33
chapter we will examine the ODB object persistence model as
well as the core database APIs in greater detail. We will
start with basic concepts and terminology in Section
- 3.1 and Section 3.2 and continue with the
+ 3.1 and Section 3.3 and continue with the
discussion of the odb::database
class in
- Section 3.3, transactions in
- Section 3.4, and connections in
- Section 3.5. The remainder of this chapter
+ Section 3.4, transactions in
+ Section 3.5, and connections in
+ Section 3.6. The remainder of this chapter
deals with the core database operations and concludes with
the discussion of ODB exceptions.
Normally, you would use object types to model real-world entities,
+ things that have their own identity. For example, in the
+ previous chapter we created a person
class to model
+ a person, which is a real-world entity. Name and age, which we
+ used as data members in our person
class are clearly
+ values. It is hard to think of age 31 or name "Joe" as having their
+ own identities.
A good test to determine whether something is an object or + a value, is to consider if other objects might reference + it. A person is clearly an object because it can be referred + to by other objects such as a spouse, an employer, or a + bank. On the other hand, a person's age or name is not + something that other objects would normally refer to.
+ +Also, when an object represents a real entity, it is easy to + choose a suitable object id. For example, for a + person there is an established notion of an identifier + (SSN, student id, passport number, etc). Another alternative + is to use a person's email address as an identifier.
+ +Note, however, that these are only guidelines. There could
+ be good reasons to make something that would normally be
+ a value an object. Consider, for example, a database that
+ stores a vast number of people. Many of the person
+ objects in this database have the same names and surnames and
+ the overhead of storing them in every object may negatively
+ affect the performance. In this case, we could make the first name
+ and last name each an object and only store pointers to
+ these objects in the person
class.
An instance of a persistent class can be in one of two states: + transient and persistent. A transient + instance only has a representation in the application's + memory and will cease to exist when the application terminates, + unless it is explicitly made persistent. In other words, a + transient instance of a persistent class behaves just like an + instance of any ordinary C++ class. A persistent instance + has a representation in both the application's memory and the + database. A persistent instance will remain even after the + application terminates unless and until it is explicitly + deleted from the database.
+ +To make a C++ class a persistent object class we declare
it as such using the db object
pragma, for
example:
While it is possible to declare a persistent class without an
- object id, such a class will have limited functionality
- (Section 12.1.6, "id
").
The object id can be of a simple or composite (Section
+ 7.2.1, "Composite Object Ids") value type. This type should be
+ default-constructible. It is also possible to declare a persistent
+ class without an object id, however, such a class will have limited
+ functionality (Section 12.1.6,
+ "id
").
The above two pragmas are the minimum required to declare a persistent class with an object id. Other pragmas can be used to fine-tune the database-related properties of a class and its members (Chapter 12, "ODB Pragma Language").
-Normally, an object class should define the default constructor. The +
Normally, a persistent class should define the default constructor. The generated database support code uses this constructor when instantiating an object from the persistent state. If we add the default constructor only for the database support code, then we - can make it private. It is also possible to have an object type - without the default constructor. However, in this case, the database - operations can only load the persistent state into an existing instance - (Section 3.8, "Loading Persistent Objects", - Section 4.4, "Query Result").
+ can make it private provided we also make theodb::access
+ class, defined in the <odb/core.hxx>
header, a
+ friend of this object class. For example:
- The object id can be of a simple or composite (Section - 7.2.1, "Composite Object Ids") value type and should be - default-constructible.
++#include <odb/core.hxx> -+ +If an object class has private or protected non-transient data - members or if its default constructor is not public, then the -
+#pragma db object +class person +{ + ... + +private: + friend class odb::access; + person () {} +}; +odb::access
class, defined in the -<odb/core.hxx>
header, should be declared a - friend of this object type. For example:
It is also possible to have an object class without the default + constructor. However, in this case, the database operations will + only be able to load the persistent state into an existing instance + (Section 3.9, "Loading Persistent Objects", + Section 4.4, "Query Result").
+ +The ODB compiler also needs access to the non-transient
+ (Section 12.4.11, "transient
")
+ data members of a persistent class. The ODB compiler can access
+ such data members directly if they are public. It can also do
+ so if they are private or protected and the odb::access
+ class is declared a friend of the object type. For example:
#include <odb/core.hxx> @@ -2223,26 +2307,80 @@ class person private: friend class odb::access; - person () {} #pragma db id unsigned long id_; + + std::string name_; +}; ++ +
If data members are not accessible directly, then the ODB
+ compiler will try to automatically find suitable accessor and
+ modifier functions. To accomplish this, the ODB compiler will
+ try to lookup common accessor and modifier names derived from
+ the data member name. Specifically, for the name_
+ data member in the above example, the ODB compiler will look
+ for accessor functions with names: get_name()
,
+ getName()
, getname()
, and just
+ name()
as well as for modifier functions with
+ names: set_name()
, setName()
,
+ setname()
, and just name()
. You can
+ also add support for custom name derivations with the
+ --accessor-regex
and --modifier-regex
+ ODB compiler options. Refer to the
+ ODB
+ Compiler Command Line Manual for details on these options.
+ The following example illustrates automatic accessor and modifier
+ discovery:
+#pragma db object +class person +{ +public: + person () {} + + ... + + unsigned long id () const; + void id (unsigned long); + + const std::string& get_name () const; + std::string& set_name (); + +private: + #pragma db id + unsigned long id_; // Uses id() for access. + + std::string name_; // Uses get_name()/set_name() for access. };+
Finally, if a data member is not directly accessible and the
+ ODB compiler was unable to discover suitable accessor and
+ modifier functions, then we can provide custom accessor
+ and modifier expressions using the db get
+ and db set
pragmas. For more information
+ on custom accessor and modifier expressions refer to
+ Section 12.4.5,
+ "get
/set
/access
".
You may be wondering whether we also have to declare value types
as persistent. We don't need to do anything special for simple value
types such as int
or std::string
since the
- ODB compiler knows how to map them to suitable database system types and
+ ODB compiler knows how to map them to suitable database types and
how to convert between the two. On the other hand, if a simple value
is unknown to the ODB compiler then we will need to provide the
- mapping to the database system type and, possibly, the code to
+ mapping to the database type and, possibly, the code to
convert between the two. For more information on how to achieve
this refer to the db type
pragma description
- in Section 12.3.1, "type
". Similar
- to object types, composite value types have to be explicitly declared
- as persistent using the db value
pragma, for example:
type
".
+
+ Similar to object classes, composite value types have to be
+ explicitly declared as persistent using the db value
+ pragma, for example:
#pragma db value @@ -2255,53 +2393,16 @@ class name };-
Composite value types are discussed in more detail in +
Note that a composite value cannot have a data member designated + as an object id since, as we have discussed earlier, values do + not have a notion of identity. A composite value type also doesn't + have to define the default constructor, unless it is used as an + element of a container. The ODB compiler uses the same mechanisms + to access data members in composite value types as in object types. + Composite value types are discussed in more detail in Section 7.2, "Composite Value Types".
-Normally, you would use object types to model real-world entities,
- things that have their own identity. For example, in the
- previous chapter we created a person
class to model
- a person, which is a real-world entity. Name and age, which we
- used as data members in our person
class are clearly
- values. It is hard to think of age 31 or name "Joe" as having their
- own identities.
A good test to determine whether something is an object or - a value, is to consider if other objects might reference - it. A person is clearly an object because it can be referred - to by other objects such as a spouse, an employer, or a - bank. On the other hand, a person's age or name is not - something that other objects would normally refer to.
- -Also, when an object represents a real entity, it is easy to - choose a suitable object id. For example, for a - person there is an established notion of an identifier - (SSN, student id, passport number, etc). Another alternative - is to use a person's email address as an identifier.
- -Note, however, that these are only guidelines. There could
- be good reasons to make something that would normally be
- a value an object. Consider, for example, a database that
- stores a vast number of people. Many of the person
- objects in this database have the same names and surnames and
- the overhead of storing them in every object may negatively
- affect the performance. In this case, we could make the first name
- and last name each an object and only store pointers to
- these objects in the person
class.
An instance of a persistent class can be in one of two states: - transient and persistent. A transient - instance only has a representation in the application's - memory and will cease to exist when the application terminates, - unless it is explicitly made persistent. In other words, a - transient instance of a persistent class behaves just like an - instance of any ordinary C++ class. A persistent instance - has a representation in both the application's memory and the - database. A persistent instance will remain even after the - application terminates unless and until it is explicitly - deleted from the database.
- -As we have seen in the previous chapter, some database operations create dynamically allocated instances of persistent classes and @@ -2422,7 +2523,7 @@ namespace accounting easy to add support for our own smart pointers, as described in Section 6.4, "Using Custom Smart Pointers".
-Before an application can make use of persistence services
offered by ODB, it has to create a database class instance. A
@@ -2539,7 +2640,7 @@ namespace odb
for various C++ constructs, refer to the schema/custom
example in the odb-examples
package.
A transaction is an atomic, consistent, isolated and durable (ACID) unit of work. Database operations can only be @@ -2652,7 +2753,7 @@ namespace odb
The database()
accessor returns the database this
transaction is working on. Similarly, the connection()
accessor returns the database connection this transaction is on
- (Section 3.5, "Connections").
The static current()
accessor returns the
currently active transaction for this thread. If there is no active
@@ -2802,7 +2903,7 @@ update_age (database& db, person& p)
}
-
The odb::connection
class represents a connection
to the database. Normally, you wouldn't work with connections
@@ -2856,7 +2957,7 @@ namespace odb
on the connection. The execute()
functions allow
us to execute native database statements on the connection.
Their semantics are equivalent to the database::execute()
- functions (Section 3.11, "Executing Native SQL
+ functions (Section 3.12, "Executing Native SQL
Statements") except that they can be legally called outside
a transaction. Finally, the database()
accessor
returns a reference to the odb::database
instance
@@ -2902,7 +3003,7 @@ c->execute ("SET FOREIGN_KEY_CHECKS = 1");
sure that a set of transactions is executed on the same
connection.
ODB uses C++ exceptions to report database operation errors. Most ODB exceptions signify hard errors or errors that cannot @@ -2913,7 +3014,7 @@ c->execute ("SET FOREIGN_KEY_CHECKS = 1"); instance, by obtaining a valid object id and trying again. The hard errors and corresponding ODB exceptions that can be thrown by each database function are described in the remainder - of this chapter with Section 3.13, "ODB Exceptions" + of this chapter with Section 3.14, "ODB Exceptions" providing a quick reference for all the ODB exceptions.
The second group of ODB exceptions signify soft or @@ -2980,7 +3081,7 @@ for (unsigned short retry_count (0); ; retry_count++) } -
A newly created instance of a persistent class is transient.
We use the database::persist()
function template
@@ -3008,8 +3109,8 @@ for (unsigned short retry_count (0); ; retry_count++)
Here and in the rest of the manual,
object_traits<T>::pointer_type
and
object_traits<T>::const_pointer_type
denote the
- unrestricted and constant object pointer types (Section
- 3.2, "Object and View Pointers"), respectively.
+ unrestricted and constant object pointer types (Section
+ 3.3, "Object and View Pointers"), respectively.
Similarly, object_traits<T>::id_type
denotes the object
id type. The odb::object_traits
template is part of the
database support code generated by the ODB compiler.
Once an object is made persistent, and you know its object id, it
can be loaded by the application using the database::load()
@@ -3172,7 +3273,7 @@ t.commit ();
identifier can be significantly faster than executing a query.
If a persistent object has been modified, we can store the updated
state in the database using the database::update()
@@ -3270,7 +3371,7 @@ t.commit ();
data members can be declared read-only (see Section
12.1.4, "readonly
(object)", Section
12.3.6, "readonly
(composite value)", and
- Section 12.4.11, "readonly
+ Section 12.4.12, "readonly
(data member)").
If an individual data member is declared read-only, then
@@ -3285,7 +3386,7 @@ t.commit ();
update()
functions for such an object will result in a
compile-time error.
To delete a persistent object's state from the database we use the
database::erase()
or database::erase_query()
@@ -3420,7 +3521,7 @@ t.commit ();
-
In some situations we may need to execute native SQL statements
instead of using the object-oriented database API described above.
@@ -3462,9 +3563,9 @@ t.commit ();
it may be necessary to execute a native statement outside a
transaction. This can be done using the
connection::execute()
functions as described in
- Section 3.5, "Connections".
Oftentimes it is useful to understand what SQL statements are executed as a result of high-level database operations. For @@ -3632,7 +3733,7 @@ odb::pgsql::database& db = ...; db.tracer (tracer); // Ok. -
In the previous sections we have already mentioned some of the
exceptions that can be thrown by the database functions. In this
@@ -3802,7 +3903,7 @@ namespace odb
not_in_transaction
,
transaction_already_finalized
) are thrown by the
odb::transaction
class and are discussed
- in Section 3.4, "Transactions".
The next two exceptions (already_in_session
, and
not_in_session
) are thrown by the odb::session
@@ -3823,20 +3924,20 @@ namespace odb
has timed out. The deadlock
exception is thrown when a
transaction deadlock is detected by the database system. These
exceptions can be thrown by any database function. See
- Section 3.6, "Error Handling and Recovery"
+ Section 3.7, "Error Handling and Recovery"
for details.
The object_already_persistent
exception is thrown
by the persist()
database function. See
- Section 3.7, "Making Objects Persistent"
+ Section 3.8, "Making Objects Persistent"
for details.
The object_not_persistent
exception is thrown
by the load()
, update()
, and
erase()
database functions. Refer to
- Section 3.8, "Loading Persistent Objects",
- Section 3.9, "Updating Persistent Objects", and
- Section 3.10, "Deleting Persistent Objects" for
+ Section 3.9, "Loading Persistent Objects",
+ Section 3.10, "Updating Persistent Objects", and
+ Section 3.11, "Deleting Persistent Objects" for
more information.
The object_changed
exception is thrown
@@ -3872,7 +3973,7 @@ namespace odb
The unknown_schema
exception is thrown by the
odb::schema_catalog
class if a schema with the specified
- name is not found. Refer to Section 3.3, "Database"
+ name is not found. Refer to Section 3.4, "Database"
for details.
The odb::exception
class is defined in the
@@ -4648,7 +4749,7 @@ private:
of person's nicknames is probably not important. To instruct the ODB
compiler to ignore the order in ordered containers we can use the
db unordered
pragma (Section 12.3.8,
- "unordered
", Section 12.4.16,
+ "unordered
", Section 12.4.17,
"unordered
"). For example:
@@ -4862,7 +4963,7 @@ private: in Section 6.4, "Using Custom Smart Pointers". Any supported smart pointer can be used in a data member as long as it can be explicitly constructed from the canonical object pointer - (Section 3.2, "Object and View Pointers"). For + (Section 3.3, "Object and View Pointers"). For example, we can use-weak_ptr
if the object pointer isshared_ptr
. @@ -4911,11 +5012,11 @@ class employeeBy default, an object pointer can be
NULL
. To specify that a pointer always points to a valid object we can - use thenot_null
pragma (Section - 12.4.5, "null
/not_null
") for + use thenot_null
pragma (Section + 12.4.6, "null
/not_null
") for single object pointers and thevalue_not_null
pragma - (Section - 12.4.21, "value_null
/value_not_null
") + (Section + 12.4.22, "value_null
/value_not_null
") for containers of object pointers. For example:@@ -5328,7 +5429,7 @@ CREATE TABLE employee ( of these references.To eliminate redundant database schema references we can use the -
@@ -5372,7 +5473,7 @@ CREATE TABLE employee ( pointer. Also note that an ordered container (Section 5.1, "Ordered Containers") of pointers that is an inverse side of a bidirectional relationship is always treated as unordered - (Section 12.4.16, "inverse
pragma (Section 12.4.12, +inverse
pragma (Section 12.4.13, "inverse
") which tells the ODB compiler that a pointer is the inverse side of a bidirectional relationship. Either side of a relationship can be made inverse. For example:unordered
") + (Section 12.4.17, "unordered
") because the contents of such a container are implicitly built from the direct side of the relationship which does not contain the element order (index). @@ -5970,14 +6071,15 @@ class basic_name example in theodb-examples
package.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 of a container, then the
+ unless it is used as an element of a container. In this case the + default constructor can be made private provided we also make the +odb::access
class - should be declared a friend of this value type. For example:odb::access
class, defined in the +<odb/core.hxx>
header, a friend of this value type. + For example:+#include <odb/core.hxx> + #pragma db value class basic_name { @@ -5991,11 +6093,17 @@ private: basic_name () {} // Needed for storing basic_name in containers. - std::string first_; - std::string last_; + ... };+The ODB compiler also needs access to the non-transient + (Section 12.4.11, "
+transient
") + data members of a composite value type. It uses the same mechanisms + as for persistent classes which are discussed in + Section 3.2, "Declaring Persistent Objects and + Values".The members of a composite value can be other value types (either simple or composite), containers (Chapter 5, "Containers"), and pointers to objects (Chapter 6, @@ -6163,8 +6271,8 @@ class person
Customizing a column name for a data member of a simple value type is straightforward: we simply specify the desired name with - the
@@ -6265,9 +6373,9 @@ CREATE TABLE person (db column
pragma (Section - 12.4.8, "column
"). For composite value + thedb column
pragma (Section + 12.4.9, "column
"). For composite value types things are slightly more complex since they are mapped to multiple columns. Consider the following example:The same principle applies when a composite value type is used as an element of a container, except that instead of
db column
, either thedb value_column
- (Section 12.4.29, "value_column
") or + (Section 12.4.30, "value_column
") ordb key_column
- (Section 12.4.28, "key_column
") + (Section 12.4.29, "key_column
") pragmas are used to specify the column prefix.When a composite value type contains a container, an extra table @@ -6311,8 +6419,8 @@ CREATE TABLE person (
To customize the container table name we can use the -
+db table
pragma (Section - 12.4.17, "table
"), for example:db table
pragma (Section + 12.4.18, "table
"), for example:#pragma db value @@ -6353,7 +6461,7 @@ CREATE TABLE person_nickname ( of a valid value in a column. While by default ODB maps values to columns that do not allow-NULL
values, it is possible to change that with thedb null
- pragma (Section 12.4.5, + pragma (Section 12.4.6, "null
/not_null
").To properly support the
NULL
semantics, the @@ -6566,11 +6674,8 @@ class person class person { public: - const std::string& - first () const; - - const std::string& - last () const; + const std::string& first () const; + const std::string& last () const; private: std::string first_; @@ -6901,7 +7006,7 @@ class contractor: public person a table in the database, just like non-abstract classes.Persistent classes in the same polymorphic hierarchy must use the - same kind of object pointer (Section 3.2, + same kind of object pointer (Section 3.3, "Object and View Pointers"). If the object pointer for the root class is specified as a template or using the special raw pointer syntax (
*
), then the ODB @@ -7234,8 +7339,8 @@ struct contractor_manager };The
erase_query()
database function (Section - 3.10, "Deleting Persistent Objects") also has limited functionality +The
erase_query()
database function (Section + 3.11, "Deleting Persistent Objects") also has limited functionality when used on polymorphic objects. Because many database implementations do not supportJOIN
clauses in the SQLDELETE
statement, only data members from the derived class being erased can @@ -7611,7 +7716,7 @@ struct employee_birth_code or the match is ambiguous, the ODB compiler will issue an error. To associate two differently-named members or to resolve an ambiguity, we can explicitly specify the member association using the -db column
pragma (Section 12.4.8, +db column
pragma (Section 12.4.9, "column
"). For example:@@ -8506,17 +8611,17 @@ namespace odb-A session is an object cache. Every time a session-enabled object is made persistent by calling the
database::persist()
function - (Section 3.7, "Making Objects Persistent"), loaded + (Section 3.8, "Making Objects Persistent"), loaded by calling thedatabase::load()
ordatabase::find()
- function (Section 3.8, "Loading Persistent Objects"), + function (Section 3.9, "Loading Persistent Objects"), or loaded by iterating over a query result (Section 4.4, "Query Result"), the pointer to the persistent object, in the form - of the canonical object pointer (Section 3.2, "Object + of the canonical object pointer (Section 3.3, "Object and View Pointers"), is stored in the session. For as long as the session is in effect, any subsequent calls to load the same object will return the cached instance. When an object's state is deleted from the database with thedatabase::erase()
function - (Section 3.10, "Deleting Persistent Objects"), the + (Section 3.11, "Deleting Persistent Objects"), the cached object pointer is removed from the session. For example:@@ -8590,7 +8695,7 @@ unsigned long id2 (save (db, p2)); // p2 is cached in s as non-const.
11 Optimistic Concurrency
-The ODB transaction model (Section 3.4, +
The ODB transaction model (Section 3.5, "Transactions") guarantees consistency as long as we perform all the database operations corresponding to a specific application transaction in a single database transaction. That is, if we load an object within a @@ -8674,7 +8779,7 @@ p.age (age);
To declare a persistent class with the optimistic concurrency model we use the
@@ -8713,7 +8818,7 @@ class personoptimistic
pragma (Section 12.1.5, "optimistic
"). We also use theversion
- pragma (Section 12.4.13, "version
") + pragma (Section 12.4.14, "version
") to specify which data member will store the object version. For example:When we call the
database::update()
function - (Section 3.9, "Updating Persistent Objects") and pass + (Section 3.10, "Updating Persistent Objects") and pass an object that has an outdated state, theodb::object_changed
exception is thrown. At this point the application has two recovery options: it can abort and potentially restart the @@ -8778,7 +8883,7 @@ p.age (age);In addition to updates, ODB also performs state mismatch detection when we are deleting an object from the database - (Section 3.10, "Deleting Persistent Objects"). + (Section 3.11, "Deleting Persistent Objects"). To understand why this can be important, consider the following application transaction:
@@ -9216,7 +9321,7 @@ class person used to specify the pointer, then the raw pointer is used by default.For a more detailed discussion of object pointers, refer to - Section 3.2, "Object and View Pointers".
+ Section 3.3, "Object and View Pointers".12.1.3
@@ -9255,7 +9360,7 @@ class contractor: public personabstract
The
readonly
specifier specifies that the persistent class is read-only. The database state of read-only objects cannot be updated. In particular, this means that you cannot call the -database::update()
function (Section 3.9, +database::update()
function (Section 3.10, "Updating Persistent Objects") for such objects. For example:@@ -9275,7 +9380,7 @@ class person read-only while the rest is treated as read-write.-Note that it is also possible to declare individual data members - (Section 12.4.11, "
@@ -9285,7 +9390,7 @@ class person has the optimistic concurrency model. A class with the optimistic concurrency model must also specify the data member that is used to store the object version using thereadonly
") + (Section 12.4.12, "readonly
") as well as composite value types (Section 12.3.6, "readonly
") as read-only.version
pragma - (Section 12.4.13, "version
"). + (Section 12.4.14, "version
"). For example:@@ -9324,18 +9429,18 @@ class personA persistent class without an object id has limited functionality. Such a class cannot be loaded with the
database::load()
- ordatabase::find()
functions (Section 3.8, + ordatabase::find()
functions (Section 3.9, "Loading Persistent Objects"), updated with the -database::update()
function (Section 3.9, +database::update()
function (Section 3.10, "Updating Persistent Objects"), or deleted with the -database::erase()
function (Section 3.10, +database::erase()
function (Section 3.11, "Deleting Persistent Objects"). To load and delete objects without ids you can use thedatabase::query()
(Chapter 4, "Querying the Database") and -database::erase_query()
(Section 3.10, +database::erase_query()
(Section 3.11, "Deleting Persistent Objects") functions, respectively. There is no way to update such objects except by using native SQL - statements (Section 3.11, "Executing Native SQL + statements (Section 3.12, "Executing Native SQL Statements").Furthermore, persistent classes without object ids cannot have container @@ -9660,8 +9765,8 @@ class employee
The standard syntax for qualified names used in the
schema
andtable
specifiers as well - as the viewcolumn
specifier (Section - 12.4.9, "column
(view)") has the + as the viewcolumn
specifier (Section + 12.4.10, "column
(view)") has the"
name.
name..."
form where, as discussed above, the leading name component can be empty to denote a fully qualified name. This form, however, @@ -10128,7 +10233,7 @@ typedef shared_ptr<person> person_ptr;The
NULL
semantics can also be specified on the - per-member basis (Section 12.4.5, + per-member basis (Section 12.4.6, "null
/not_null
"). If both a type and a member havenull
/not_null
specifiers, then the member specifier takes precedence. If a member specifier @@ -10181,7 +10286,7 @@ class personThe semantics of the
default
specifier for a value type are similar to those of thedefault
specifier for a - data member (Section 12.4.6, + data member (Section 12.4.7, "default
").12.3.5
@@ -10204,7 +10309,7 @@ class personoptions
The semantics of the
options
specifier for a value type are similar to those of theoptions
specifier for a - data member (Section 12.4.7, + data member (Section 12.4.8, "options
").12.3.6
@@ -10212,7 +10317,7 @@ class personreadonly
The
@@ -10233,7 +10338,7 @@ class person_name read-only while the rest is treated as read-write.readonly
specifier specifies that the composite value type is read-only. Changes to data members of a read-only composite value type are ignored when updating the database - state of an object (Section 3.9, "Updating Persistent + state of an object (Section 3.10, "Updating Persistent Objects") containing such a value type. Note that this specifier is only valid for composite value types. For example:Note that it is also possible to declare individual data members - (Section 12.4.11, "
@@ -10407,7 +10512,7 @@ typedef std::vector<std::string> nicknames;readonly
") + (Section 12.4.12, "readonly
") as well as whole objects (Section 12.1.4, "readonly
") as read-only.The semantics of the
@@ -10424,7 +10529,7 @@ typedef std::vector<std::string> nicknames;id_options
specifier for a container type are similar to those of theid_options
specifier for - a container data member (Section 12.4.22, + a container data member (Section 12.4.23, "id_options
").The semantics of the
@@ -10441,7 +10546,7 @@ typedef std::map<std::string, std::string> properties;index_options
specifier for a container type are similar to those of theindex_options
specifier for - a container data member (Section 12.4.23, + a container data member (Section 12.4.24, "index_options
").The semantics of the
@@ -10458,7 +10563,7 @@ typedef std::set<std::string> nicknames;key_options
specifier for a container type are similar to those of thekey_options
specifier for - a container data member (Section 12.4.24, + a container data member (Section 12.4.25, "key_options
").The semantics of the
@@ -10561,153 +10666,159 @@ typedef std::map<unsigned short, float> age_weight_map;value_options
specifier for a container type are similar to those of thevalue_options
specifier for - a container data member (Section 12.4.25, + a container data member (Section 12.4.26, "value_options
").+ + ++ get
/set
/access
member accessor/modifier expressions +12.4.5 +null
/not_null
member can/cannot be -NULL
12.4.5 +12.4.6 default
default value for a member -12.4.6 +12.4.7 options
database options for a member -12.4.7 +12.4.8 column
column name for a member of an object or composite value -12.4.8 +12.4.9 column
column name for a member of a view -12.4.9 +12.4.10 transient
member is not stored in the database -12.4.10 +12.4.11 readonly
member is read-only -12.4.11 +12.4.12 inverse
member is an inverse side of a bidirectional relationship -12.4.12 +12.4.13 version
member stores object version -12.4.13 +12.4.14 index
define database index for a member -12.4.14 +12.4.15 unique
define unique database index for a member -12.4.15 +12.4.16 unordered
ordered container should be stored unordered -12.4.16 +12.4.17 table
table name for a container -12.4.17 +12.4.18 index_type
database type for a container's index type -12.4.18 +12.4.19 key_type
database type for a container's key type -12.4.19 +12.4.20 value_type
database type for a container's value type -12.4.20 +12.4.21 value_null
/value_not_null
container's value can/cannot be -NULL
12.4.21 +12.4.22 id_options
database options for a container's id column -12.4.22 +12.4.23 index_options
database options for a container's index column -12.4.23 +12.4.24 key_options
database options for a container's key column -12.4.24 +12.4.25 value_options
database options for a container's value column -12.4.25 +12.4.26 id_column
column name for a container's object id -12.4.26 +12.4.27 index_column
column name for a container's index -12.4.27 +12.4.28 key_column
column name for a container's key -12.4.28 +12.4.29 @@ -10773,7 +10884,7 @@ class person is a safe choice. value_column
column name for a container's value -12.4.29 +12.4.30 For additional information on the automatic identifier assignment, - refer to Section 3.7, "Making Objects Persistent".
+ refer to Section 3.8, "Making Objects Persistent".Note also that the
@@ -10794,8 +10905,8 @@ class person };auto
specifier cannot be specified for data members of composite value types or views.The
null
andnot_null
(Section - 12.4.5, "null
/not_null
") specifiers +The
null
andnot_null
(Section + 12.4.6, "null
/not_null
") specifiers can be used to control the NULL semantics of a data member.12.4.4
@@ -10831,7 +10942,234 @@ class person };id_type
12.4.5
+null
/not_null
12.4.5
+ +get
/set
/access
The
+ +get
andset
specifiers specify the + data member accessor and modifier expressions, respectively. If + provided, the generated database support code will use these + expressions to access and modify the data member when performing + database operations. Theaccess
specifier can be used + as a shortcut to specify both the accessor and modifier if they + happen to be the same.In its simplest form the accessor or modifier expression can be + just a name. Such a name should resolve either to another data + member of the same type or to a suitable accessor or modifier + member function. For example:
+ ++#pragma db object +class person +{ + ... + +public: + const std::string& name () const; + void name (const std::string&); +private: + #pragma db access(name) + std::string name_; +}; ++ +A suitable accessor function is a
+ +const
member function + that takes no arguments and whose return value can be implicitly + converted to theconst
reference to the member type + (const std::string&
in the example above). + An accessor function that returns aconst
reference + to the data member is called by-reference accessor. + Otherwise, it is called by-value accessor.A suitable modifier function can be of two forms. It can be the + so called by-reference modifier which is a member function + that takes no arguments and returns a non-
+ +const
reference + to the data member (std::string&
in the example above). + Alternatively, it can be the so called by-value modifier which + is a member function taking a single argument — the new value + — that can be implicitly initialized from a variable of the member + type (std::string
in the example above). The return value + of a by-value modifier, if any, is ignored. If both by-reference and + by-value modifiers are available, then ODB prefers the by-reference + version since it is more efficient. For example:+#pragma db object +class person +{ + ... + +public: + std::string get_name () const; // By-value accessor. + std::string& set_name (); // By-reference modifier. + void set_name (std::string const&); // By-value modifier. +private: + #pragma db get(get_name) \ // Uses by-value accessor. + set(set_name) // Uses by-reference modifier. + std::string name_; +}; ++ +Note that in many cases it is not necessary to specify accessor and + modifier functions explicitly since the ODB compiler will try to + discover them automatically in case the data member will be inaccessible + to the generated code. In particular, in both of the above examples + the ODB compiler would have successfully discovered the necessary + functions. For more information on this functionality, refer to + Section 3.2, "Declaring Persistent Objects and + Values".
+ +Note also that by-value accessors and by-value modifiers cannot be + used for certain data members in certain situations. These limitations + are discussed in more detail later in this section.
+ +Accessor and modifier expressions can be more elaborate than simple + names. An accessor expression is any C++ expression that can be + used to initialize a
+ +const
reference to the member + type. Similar to accessor functions, which are just a special case + of accessor expressions, an accessor expression that evaluates to a +const
reference to the data member is called + by-reference accessor expression. Otherwise, it is + called by-value accessor expression.Modifier expressions can also be of two forms: by-reference + modifier expression and by-value modifier expression + (again, modifier functions are just a special case of modifier + expressions). A by-reference modifier expression is any C++ + expression that evaluates to the non-
+ +const
reference + to the member type. A by-value modifier expression can be a + single or multiple (separated by semicolon) C++ statements + with the effect of setting the new member value.There are two special placeholders that are recognized by the + ODB compiler in accessor and modifier expressions. The first + is the
+ +this
keyword which denotes a reference + (note: not a pointer) to the persistent object. In accessor + expressions this reference isconst
while in + modifier expressions it is non-const
. If an + expression does not contain thethis
placeholder, + then the ODB compiler automatically prefixes it withthis.
+ sequence.The second placeholder, the
+ +(?)
sequence, is used + to denote the new value in by-value modifier expressions. The + ODB compiler replaces the question mark with the variable name, + keeping the surrounding parenthesis. The following example shows + a few more interesting accessor and modifier expressions:+#pragma db value +struct point +{ + point (int, int); + + int x; + int y; +}; + +#pragma db object +class person +{ + ... + + public: + const char* name () const; + void name (const char*); + private: + #pragma db get(std::string (this.name ())) \ + set(name ((?).c_str ())) // The same as this.name (...). + std::string name_; + + public: + const std::unique_ptr<account>& acc () const; + void acc (std::unique_ptr<account>); + private: + #pragma db set(acc (std::move (?))) + std::unique_ptr<account> acc_; + + public: + int loc_x () const + int loc_y () const + void loc_x (int); + void loc_y (int); + private: + #pragma db get(point (this.loc_x (), this.loc_y ())) \ + set(this.loc_x ((?).x); this.loc_y ((?).y)) + point loc_; +}; ++ +When the data member is of an array type, then the terms "reference" + and "member type" in the above discussion should be replaced with + "pointer" and "array element type", respectively. That is, the accessor + expression for an array member is any C++ expression that can be + used to initialize a
+ +const
pointer to the array + element type, and so on. The following example shows common + accessor and modifier signatures for array members:+#pragma db object +class person +{ + ... + + public: + const char* id () const; // By-reference accessor. + void id (const char*); // By-value modifier. + private: + char id_[16]; + + public: + const char* pub_key () const; // By-reference accessor. + char* pub_key (); // By-reference modifier. + private: + char pub_key_[2048]; +}; ++ +Accessor and modifier expressions can be used with data members + of simple value, composite value, container, and object pointer + types. They can also be used for data members in persistent classes, + composite value types, and views. There are, however, certain + limitations when it comes to using by-value accessor and modifier + expressions. First of all, if a by-value modifier is used, then + the data member type should be default-constructible. Furthermore, + a composite value type that has a container member cannot + be modified with a by-value modifier. Only a by-reference modifier + expression can be used. The ODB compiler will detect such cases + and issue diagnostics. For example:
+ ++#pragma db value +struct name +{ + std::string first_; + std::string last_; + std::vector<std::string> aliases_; +}; + +#pragma db object +class person +{ + ... + +public: + const name& name () const; + void name (const name&); +private: + #pragma db access(name) // Error: by-value modifier. + name name_; +}; ++ +In certain database systems it is also not possible to use by-value + accessor and modifier expression with certain database types. + The ODB compiler is only able to detect such cases and issue diagnostics + if you specified accessor/modifier function names as opposed to custom + expressions. For more information on these database and type-specific + limitations, refer to the "Limitations" sections in Part + II, "Database Systems".
+ +12.4.6
null
/not_null
The
@@ -10886,7 +11224,7 @@ class account discussion of thenull
andnot_null
specifiers specify that the data member can or cannot beNULL
, respectively. @@ -10844,7 +11182,7 @@ class person of each value type. Consult the relevant documentation to find out more about theNULL
semantics for such value types. A data member containing the object id (Section - 12.4.1, "id
" ) is automatically treated as not + 12.4.1, "id
") is automatically treated as not allowing aNULL
value. Data members that allowNULL
values are mapped in a relational database to columns that allowNULL
values. For example:NULL
semantics for object pointers, refer to Chapter 6, "Relationships". -12.4.6
+default
12.4.7
default
The
@@ -10907,8 +11245,8 @@ class person an integer literal, a floating point literal, a string literal, or an enumerator name. If you need to specify a default value that is an expression, for example an SQL function call, then you can use - thedefault
specifier specifies the database default value that should be used for the data member. For example:options
specifier (Section - 12.4.7, "options
") instead. For example: + theoptions
specifier (Section + 12.4.8, "options
") instead. For example:enum gender {male, female, undisclosed}; @@ -10994,7 +11332,7 @@ class person-Additionally, the
-default
specifier cannot be specified for view data members.12.4.7
+options
12.4.8
options
The
options
specifier specifies additional column definition options that should be used for the data member. For @@ -11042,9 +11380,9 @@ class personODB provides dedicated specifiers for specifying column types (Section 12.4.3, "
@@ -11052,7 +11390,7 @@ class persontype
"), -NULL
constraints (Section 12.4.5, +NULL
constraints (Section 12.4.6, "null
/not_null
"), and default - values (Section 12.4.6, "default
"). + values (Section 12.4.7, "default
"). For ODB to function correctly these specifiers should always be used instead of the opaqueoptions
specifier for these components of a column definition.Note also that the
-options
specifier cannot be specified for view data members.12.4.8
+column
(object, composite value)12.4.9
column
(object, composite value)The
-column
specifier specifies the column name that should be used to store the data member of a persistent class @@ -11078,7 +11416,7 @@ class person the common data member name decorations, such as leading and trailing underscores, them_
prefix, etc.12.4.9
+column
(view)12.4.10
column
(view)The
-column
specifier can be used to specify the associated object data member, the potentially qualified column name, or the column @@ -11086,7 +11424,7 @@ class person refer to Section 9.1, "Object Views" and Section 9.2, "Table Views".12.4.10
+transient
12.4.11
transient
The
@@ -11108,16 +11446,16 @@ class person references that are only meaningful in the application's memory, as well as utility members such as mutexes, etc. -transient
specifier instructs the ODB compiler not to store the data member in the database. For example:12.4.11
+readonly
12.4.12
readonly
The
@@ -11201,7 +11539,7 @@ class person as well as whole objects (Section 12.1.4, "readonly
specifier specifies that the data member of an object or composite value type is read-only. Changes to a read-only data member are ignored when updating the database state of an object - (Section 3.9, "Updating Persistent Objects") + (Section 3.10, "Updating Persistent Objects") containing such a member. Since views are read-only, it is not necessary to use this specifier for view data members. Object id (Section 12.4.1, "id
") - and inverse (Section 12.4.12, + and inverse (Section 12.4.13, "inverse
") data members are automatically treated as read-only and must not be explicitly declared as such. For example:readonly
") as read-only. -12.4.12
+inverse
12.4.13
inverse
The
+ (Section 12.4.17, "inverse
specifier specifies that the data member of an object pointer or a container of object pointers type is an @@ -11239,12 +11577,12 @@ class person relationship information. Only ordered and set containers can be used for inverse members. If an inverse member is of an ordered container type, it is automatically marked as unordered - (Section 12.4.16, "unordered
").unordered
").For a more detailed discussion of inverse members, refer to Section 6.2, "Bidirectional Relationships".
-12.4.13
+version
12.4.14
version
The
version
specifier specifies that the data member stores the object version used to support optimistic concurrency. If a class @@ -11274,7 +11612,7 @@ class personFor a more detailed discussion of optimistic concurrency, refer to Chapter 11, "Optimistic Concurrency".
-12.4.14
+index
12.4.15
index
The
@@ -11293,7 +11631,7 @@ class personindex
specifier instructs the ODB compiler to define a database index for the data member. For example:For more information on defining database indexes, refer to Section 12.6, "Index Definition Pragmas".
-12.4.15
+unique
12.4.16
unique
The
@@ -11312,7 +11650,7 @@ class personindex
specifier instructs the ODB compiler to define a unique database index for the data member. For example:For more information on defining database indexes, refer to Section 12.6, "Index Definition Pragmas".
-12.4.16
+unordered
12.4.17
unordered
The
-unordered
specifier specifies that the member of an ordered container type should be stored unordered in the database. @@ -11335,7 +11673,7 @@ class person storage in the database, refer to Section 5.1, "Ordered Containers".12.4.17
+table
12.4.18
table
The
@@ -11383,7 +11721,7 @@ class person qualified names, refer to Section 12.1.8, "table
specifier specifies the table name that should be used to store the contents of the container member. For example:schema
". -12.4.18
+index_type
12.4.19
index_type
The
index_type
specifier specifies the native database type that should be used for an ordered container's @@ -11403,7 +11741,7 @@ class person };12.4.19
+key_type
12.4.20
key_type
The
key_type
specifier specifies the native database type that should be used for a map container's @@ -11423,7 +11761,7 @@ class person };
value_type
value_type
The value_type
specifier specifies the native
database type that should be used for a container's
@@ -11444,18 +11782,18 @@ class person
The value_null
and value_not_null
- (Section 12.4.21,
+ (Section 12.4.22,
"value_null
/value_not_null
") specifiers
can be used to control the NULL semantics of a value column.
value_null
/value_not_null
value_null
/value_not_null
The value_null
and value_not_null
specifiers
specify that a container's element value for the data member can or
cannot be NULL
, respectively. The semantics of
value_null
and value_not_null
are similar
to those of the null
and not_null
specifiers
- (Section 12.4.5, "null
/not_null
").
+ (Section 12.4.6, "null
/not_null
").
For example:
@@ -11481,7 +11819,7 @@ class account Multiset Containers") the element value is automatically treated as not allowing aNULL
value. -12.4.22
+id_options
12.4.23
id_options
The
id_options
specifier specifies additional column definition options that should be used for a container's @@ -11502,10 +11840,10 @@ class person
The semantics of id_options
are similar to those
- of the options
specifier (Section
- 12.4.7, "options
").
options
specifier (Section
+ 12.4.8, "options
").
- index_options
index_options
The index_options
specifier specifies additional
column definition options that should be used for a container's
@@ -11523,10 +11861,10 @@ class person
The semantics of index_options
are similar to those
- of the options
specifier (Section
- 12.4.7, "options
").
options
specifier (Section
+ 12.4.8, "options
").
- key_options
key_options
The key_options
specifier specifies additional
column definition options that should be used for a container's
@@ -11544,10 +11882,10 @@ class person
The semantics of key_options
are similar to those
- of the options
specifier (Section
- 12.4.7, "options
").
options
specifier (Section
+ 12.4.8, "options
").
- value_options
value_options
The value_options
specifier specifies additional
column definition options that should be used for a container's
@@ -11565,17 +11903,17 @@ class person
The semantics of value_options
are similar to those
- of the options
specifier (Section
- 12.4.7, "options
").
options
specifier (Section
+ 12.4.8, "options
").
- id_column
id_column
The id_column
specifier specifies the column
name that should be used to store the object id in a
container's table for the data member. The semantics of
id_column
are similar to those of the
column
specifier
- (Section 12.4.8, "column
").
+ (Section 12.4.9, "column
").
For example:
@@ -11592,14 +11930,14 @@ class personIf the column name is not specified, then
-object_id
is used by default.12.4.27
+index_column
12.4.28
index_column
The
index_column
specifier specifies the column name that should be used to store the element index in an ordered container's table for the data member. The semantics ofindex_column
are similar to those of thecolumn
specifier - (Section 12.4.8, "column
"). + (Section 12.4.9, "column
"). For example:@@ -11616,14 +11954,14 @@ class personIf the column name is not specified, then
-index
is used by default.12.4.28
+key_column
12.4.29
key_column
The
key_column
specifier specifies the column name that should be used to store the key in a map container's table for the data member. The semantics ofkey_column
are similar to those of thecolumn
specifier - (Section 12.4.8, "column
"). + (Section 12.4.9, "column
"). For example:@@ -11640,14 +11978,14 @@ class personIf the column name is not specified, then
-key
is used by default.12.4.29
+value_column
12.4.30
value_column
The
value_column
specifier specifies the column name that should be used to store the element value in a container's table for the data member. The semantics ofvalue_column
are similar to those of thecolumn
specifier - (Section 12.4.8, "column
"). + (Section 12.4.9, "column
"). For example:@@ -11778,7 +12116,7 @@ namespace accountingFor a more detailed discussion of object and view pointers, refer - to Section 3.2, "Object and View Pointers".
+ to Section 3.3, "Object and View Pointers".12.5.2
@@ -11959,9 +12297,9 @@ class objecttable
ODB also offers a shortcut for defining an index with the default method and options for a single data member. Such an index can - be defined using the
index
(Section - 12.4.14, "index
") orunique
- (Section 12.4.15, "unique
") + be defined using theindex
(Section + 12.4.15, "index
") orunique
+ (Section 12.4.16, "unique
") member specifier. For example:@@ -12121,7 +12459,7 @@ class object The conversion expressions are regular expression substitutions. They must contain the special(?)
placeholder which will be replaced with the actual value to be converted. Turning on SQL - statement tracing (Section 3.12, "Tracing SQL + statement tracing (Section 3.13, "Tracing SQL Statement Execution") can be useful for debugging conversion expressions. This allows you to see the substituted expressions as used in the actual statements. @@ -12882,7 +13220,7 @@ namespace odbFor more information on the
odb::connection
interface, - refer to Section 3.5, "Connections". The first + refer to Section 3.6, "Connections". The first overloadedmysql::connection
constructor establishes a new MySQL connection. The second constructor allows us to create aconnection
instance by providing an already connected @@ -13447,7 +13785,7 @@ auto_ptr<odb::database> db (The
begin_immediate()
andbegin_exclusive()
functions are the SQLite-specific extensions to the standardodb::database::begin()
function (see - Section 3.4, "Transactions"). They allow us + Section 3.5, "Transactions"). They allow us to start an immediate (BEGIN IMMEDIATE
) and an exclusive (BEGIN EXCLUSIVE
) SQLite transaction, respectively. For more information on the semantics of the immediate and exclusive @@ -13491,7 +13829,7 @@ namespace odbFor more information on the
@@ -13819,7 +14157,7 @@ class personodb::connection
interface, - refer to Section 3.5, "Connections". The first + refer to Section 3.6, "Connections". The first overloadedsqlite::connection
constructor opens a new SQLite connection. Theextra_flags
argument can be used to specify extrasqlite3_open_v2()
flags @@ -13774,7 +14112,7 @@ namespace odb SQLite results is the unavailability of theresult::size()
function. If you call this function on an SQLite query result, then theodb::result_not_cached
exception - (Section 3.13, "ODB Exceptions") is always + (Section 3.14, "ODB Exceptions") is always thrown. Future versions of the SQLite ODB runtime library may add support for result caching.If foreign key constraints checking is disabled or not available, then inconsistencies in object relationships will not be detected. Furthermore, using the
@@ -13874,8 +14212,8 @@ CREATE TABLE Employee ( to distinguish between the duplicate primary key and other constraint violations. As a result, when making an object persistent, the SQLite ODB runtime will translate all constraint violation errors to the -erase_query()
function - (Section 3.10, "Deleting Persistent Objects") + (Section 3.11, "Deleting Persistent Objects") to delete persistent objects that contain containers will not work correctly. Container data for such objects will not be deleted.object_already_persistent
exception (Section - 3.13, "ODB Exceptions"). +object_already_persistent
exception (Section + 3.14, "ODB Exceptions").14.5.5 Sharing of Queries
@@ -14276,7 +14614,7 @@ namespace odbFor more information on the
+ (Section 3.14, "ODB Exceptions").odb::connection
interface, - refer to Section 3.5, "Connections". The first + refer to Section 3.6, "Connections". The first overloadedpgsql::connection
constructor establishes a new PostgreSQL connection. The second constructor allows us to create aconnection
instance by providing an already connected @@ -14519,7 +14857,7 @@ CREATE TABLE Employee ( constraint violations. As a result, when making an object persistent, the PostgreSQL ODB runtime will translate all unique constraint violation errors to theobject_already_persistent
exception - (Section 3.13, "ODB Exceptions").15.5.4 Date-Time Format
@@ -14715,7 +15053,7 @@ class object in the generated schema, columns of these types are declared asNULL
even if explicitly declared asNOT NULL
with thedb not_null
pragma - (Section 12.4.5, "null/not_null
"), + (Section 12.4.6, "null/not_null
"), except for primary key columns. This also means that for object ids that are mapped to these Oracle types, an empty string is an invalid value. @@ -14986,7 +15324,7 @@ namespace odb
For more information on the odb::connection
interface, refer
- to Section 3.5, "Connections". The first overloaded
+ to Section 3.6, "Connections". The first overloaded
oracle::connection
constructor creates a new OCI service
context. The OCI statement caching is enabled for the underlying session
while the OCI connection pooling and session pooling are not used. The
@@ -15299,7 +15637,7 @@ class long_class_name
the uncached Oracle results is the unavailability of the
result::size()
function. If you call this function on
an Oracle query result, then the odb::result_not_cached
- exception (Section 3.13, "ODB Exceptions") is
+ exception (Section 3.14, "ODB Exceptions") is
always thrown. Future versions of the Oracle ODB runtime library
may add support for result caching.
object_already_persistent
exception
- (Section 3.13, "ODB Exceptions").
+ (Section 3.14, "ODB Exceptions").
FLOAT
and
NUMBER
TypesAs discussed in Section 12.4.5,
+ "get
/set
/access
", by-value
+ accessor and modifier expressions cannot be used with data members
+ of Oracle large object (LOB) data types: BLOB
,
+ CLOB
, and NCLOB
. The Oracle ODB runtime
+ uses streaming for reading/writing LOB data directly from/to
+ data members. As a result, by-reference accessors and modifiers
+ should be used for these data types.
When the For more information on the index
pragma (Section 12.6,
@@ -16011,7 +16360,7 @@ namespace odb
odb::connection
interface, refer
- to Section 3.5, "Connections". The first overloaded
+ to Section 3.6, "Connections". The first overloaded
mssql::connection
constructor creates a new ODBC connection.
The created connection is configured to use the manual commit mode with
multiple active result sets (MARS) enabled. The second constructor allows
@@ -16277,8 +16626,8 @@ namespace odb
them. The only limitation of the uncached SQL Server results is the
unavailability of the result::size()
function. If you
call this function on an SQL Server query result, then the
- odb::result_not_cached
exception (Section
- 3.13, "ODB Exceptions") is always thrown. Future versions of the
+ odb::result_not_cached
exception (Section
+ 3.14, "ODB Exceptions") is always thrown. Future versions of the
SQL Server ODB runtime library may add support for result caching.17.5.2 Foreign Key Constraints
@@ -16297,7 +16646,7 @@ namespace odb
constraint violations. As a result, when making an object persistent,
the SQL Server ODB runtime will translate all unique constraint violation
errors to the object_already_persistent
exception
- (Section 3.13, "ODB Exceptions").
SQL Server always returns zero as the number of affected rows
for DDL statements. In particular, this means that the
- database::execute()
(Section 3.11,
+ database::execute()
(Section 3.12,
"Executing Native SQL Statements") function will always
return zero for such statements.
--mssql-server-version 9.0
ODB
compiler option.
+ As discussed in Section 12.4.5,
+ "get
/set
/access
", by-value
+ accessor and modifier expressions cannot be used with data members
+ of long data types. The SQL Server ODB runtime uses streaming for
+ reading/writing long data directly from/to data members. As a result,
+ by-reference accessors and modifiers should be used for these data
+ types.
When the index
pragma (Section 12.6,
@@ -16453,7 +16812,7 @@ odb --profile boost/date-time ...
system. All such exceptions derive from the
odb::boost::exception
class which in turn derives from
the root of the ODB exception hierarchy, class odb::exception
- (Section 3.13, "ODB Exceptions"). The
+ (Section 3.14, "ODB Exceptions"). The
odb::boost::exception
class is defined in the
<odb/boost/exception.hxx>
header file and has the
same interface as odb::exception
. The concrete exceptions
@@ -16471,7 +16830,7 @@ odb --profile boost/date-time ...
The currently supported smart pointers are
Besides providing persistence support for the above smart pointers,
the The currently supported smart pointers are
Besides providing persistence support for the above smart pointers,
the boost::shared_ptr
and boost::weak_ptr
. For
more information on using smart pointers as pointers to objects and
- views, refer to Section 3.2, "Object and View Pointers"
+ views, refer to Section 3.3, "Object and View Pointers"
and Chapter 6, "Relationships". For more information
on using smart pointers as pointers to values, refer to
Section 7.3, "Pointers and NULL
Value
@@ -16523,7 +16882,7 @@ class employee
smart-ptr
sub-profile also changes the default
- pointer (Section 3.2, "Object and View Pointers")
+ pointer (Section 3.3, "Object and View Pointers")
to boost::shared_ptr
. In particular, this means that
database functions that return dynamically allocated objects and views
will return them as boost::shared_ptr
pointers. To override
@@ -17008,7 +17367,7 @@ class person
system. All such exceptions derive from the
odb::qt::exception
class which in turn derives from
the root of the ODB exception hierarchy, class odb::exception
- (Section 3.13, "ODB Exceptions"). The
+ (Section 3.14, "ODB Exceptions"). The
odb::qt::exception
class is defined in the
<odb/qt/exception.hxx>
header file and has the
same interface as odb::exception
. The concrete exceptions
@@ -17297,7 +17656,7 @@ class Person
QSharedPointer
and QWeakPointer
.
For more information on using smart pointers as pointers to objects
- and views, refer to Section 3.2, "Object and View
+ and views, refer to Section 3.3, "Object and View
Pointers" and Chapter 6, "Relationships". For
more information on using smart pointers as pointers to values, refer
to Section 7.3, "Pointers and NULL
Value
@@ -17349,7 +17708,7 @@ class Employee
smart-ptr
sub-profile also changes the default
- pointer (Section 3.2, "Object and View Pointers")
+ pointer (Section 3.3, "Object and View Pointers")
to QSharedPointer
. In particular, this means that
database functions that return dynamically allocated objects and views
will return them as QSharedPointer
pointers. To override
--
cgit v1.1