From f3822e168d300f0fa8149db00ce52c03632d00ac Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 22 Sep 2010 16:07:31 +0200 Subject: Next two chapters --- doc/manual.xhtml | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 389 insertions(+), 9 deletions(-) (limited to 'doc') diff --git a/doc/manual.xhtml b/doc/manual.xhtml index 37e1828..7bf7bbf 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -249,6 +249,272 @@ +

Preface

+ +

As more and more aspects of our lives become increasinly dependant + on software systems, more and more applications are required to + save the data they work on in persistent storage. Database + management systems and, in particular, relational database + management systems (RDBMS) are a common answer to this requirement. + However, while the application development techniques have evolved + significantly over the past decades, the relational databases stayed + relatively unchanged. In particular, this led to the now famous + mismatch between the object-oriented models used by many modern + applications and the relational models still used by RDBMS.

+ +

While relational databases may be inconvenient to use from modern + programming languages, they are still the only rational choice for + many applications due to their maturity, reliability, as well as + the avaliability of tools and alternative implementations.

+ +

To allow application developers to utilize relational databases + from their object-oriented applications, a technique called + object-relational mapping (ORM) is often used. It involves + conversion between objects in the application's memory and + their relational representation in the database. While + object-relational mapping can be done manually, automated ORM + systems are available for most programming languages. ODB is + an ORM system for C++.

+ +

About This Document

+ +

The goal of this manual is to provide you with an understanding + of the object persistence model as implemented by ODB and to + allow you to efficiently evaluate it against your project's + technical requirements. As such, this document is intended for + C++ application developers and software architects who are looking + for a C++ object persistence solution. Prior experience with C++ + is required to understand this document. Basic understanding of + relational database systems is advantageous but not expected + or required.

+ + +

More Information

+ +

Beyond this manual, you may also find the following sources of + information useful:

+ + + + + + + +

1 Introduction

+ +

ODB is an object-relational mapping (ORM) system for C++. It provides + tools, APIs, and library support that allow you to persist C++ objects + to a relational database (RDBMS) without having to deal with tables, + columns, or SQL and without manually writing any of the mapping code.

+ +

ODB is highly flexible and customizable. It can either completely + hide the relational nature of the underlying database or expose + some of the details as required. For example, you can automatically + map basic C++ types to suitable SQL types, generate the relational + database schema for your persistent clases, and use simple, safe, + and yet powerful object query language instead of SQL. Or you can + assign SQL types to individual data members, use the existing + database schema, and run native SQL SELECT queries.

+ +

ODB is not a framework. It does not dictate how you should write + your application. Rather it is designed to fit into your + style and architecture by only handling object persistence + and not interfering with any other functionality. There is + no common base type that all persistent classes should derive + from nor there are any restrictions on the data member types + in persistent classes. Existing classes can be made persistent + with little or nor modifications.

+ +

ODB has been designed for high performance and low memory + overhead. Prepared statements are used to send and receive + object state in binary format instead of text which reduces + the load on the application and the database server. Extensive + caching of connections, prepared statements, and buffers saves + time and resources on connection establishment, statement parsing + and memory allocations. For each supported database system the + native C API is used instead of ODBC or higher-level wrapper + APIs to reduce overhead and provide the most efficient implementation + for each database operation. Finally, persistent classes have + zero memory overhead. There are no hidden "database" members + that each class must have nor there are per-object data structures + allocated by ODB.

+ +

In this chapter we present a high-level overview of ODB. We will + start with the ODB architecture in Section 1.1. + Section 1.2 will then outline the workflow of + building an application that uses ODB. We will conclude this + chapter with Section 1.3 that discusses the + drawbacks of the traditional way of saving C++ objects to + relational databases and benefits of using ODB for object + persistence. The next chapter takes the more hands-on approach + and shows the concrete steps necessary to implement object + persistence in a "Hello World" application.

+ +

1.1 Architecture and Workflow

+ +

From the application developer's perspective ODB + consist of three main components: the ODB compiler, the common + runtime library, called libodb, and the + database-specific runtime libraries, called + libodb-<databse> where <databse> is + the name of the database system this runtime + is for, for example, libodb-mysql. For instance, + if the application is going to use the MySQL database for + object persistence, then the three ODB components that this + application will use are the ODB compiler, libodb + and libodb-mysql.

+ +

The ODB compiler generates the database support code for + persistent classes in your application. The input to the ODB + compiler is one or more C++ header files defining C++ classes + that you want to make persistent. For each input header file + the ODB compiler generates a set of C++ source files implementing + conversion between persistent C++ classes defined in this + header and their database representation. The ODB compiler + can also generate a database schema file that creates tables + necessary to store the persistent classes.

+ +

The ODB compiler is a real C++ compiler except that it produces + C++ instead of assembly or machine code. In particular, it is not + an ad-hoc header pre-processor that is only capable of recognizing + a subset of C++. ODB is capable of parsing any standard C++ code.

+ +

The common runtime library defines database system-independant + interfaces that your application can use to manipulate persistent + objects. The database-specific runtime library provides implementations + of these interfaces for a concrete database as well as other + database-specific utilities that are used by the generated code. + Normally, the application does not use the database-specific + runtime library directly but rather works with it via the common + interfaces from libodb. The following diagram shows + the object persistence architecture of an application that uses + MySQL as the underlying database system:

+ +

@@ arch diagram

+ +

The ODB system also defines two special-purpose languages: + the ODB Pragma Language and ODB Query Language. The ODB Pragma + Language is used to comminicate various properties of persistent + classes to the ODB compiler by means of special #pragma + directives embedded in the C++ header files. It controls such aspects + of the object-relational mapping as names of tables and columns that + are used for persistent classes and their members or mapping between + C++ types and database types.

+ +

The ODB Query Language is an object-oriented database query + language that can be used to search for objects matching + a certain criteria. It is modeled after and is integrated into + C++ allowing you to write expressive and safe queries that look + and feel like ordinary C++.

+ +

The use of the ODB compiler to generate database support code + adds an additional step to your application build sequence. The + following diagram shows the typical build workflow of an application + that uses ODB:

+ +

@@ flow diagram

+ +

1.2 Benefits

+ +

The traditional way of saving C++ objects to relational databases + involves manually writen code that converts between the database + and C++ representations of each persistent class. The actions that + such code usually performs include conversion between C++ values and + strings or database types, preparation and execution of SQL queries, + and result set handling. Writing this code manually has the following + drawbacks:

+ + + +

In contrast, using ODB to implement C++ object persistence has the + following benefits:

+ + + +

Overall, ODB provides an easy to use yet flexible and powerful + object-relational mapping (ORM) system for C++. Unlike other + ORM implementation for C++ that still require you to write + database conversion or member registration code for each + persistent class, ODB keeps persistent classes purely + declarational. The functional part, the database conversion + code, is automatically generated by the ODB compiler from + these declarations.

+ @@ -1043,7 +1309,7 @@ Hello, Joe! -

3 Working Title

+

3 Working with Persistent Objects

@@

@@ -1257,7 +1523,8 @@ Hello, Joe! instance via this interface unless there is a specific functionality that your application depends on and which is only exposed by a particular system's database - class.

+ class. You will need to include the <odb/database.hxx> + header file to make this class available in your application.

The odb::database interface defines functions for starting transactions and manipulating persistent objects. @@ -1309,11 +1576,11 @@ Hello, Joe!

A transaction is started by calling the database::begin_transaction() function. The returned transaction handle is stored in - an instance of the odb::transaction class which is - defined in the <odb/transaction.hxx> header file. - A source code fragment that uses ODB transactions should include - this header file. The odb::transaction class has - the following interface:

+ an instance of the odb::transaction class. + You will need to include the <odb/transaction.hxx> + header file to make this class available in your application. + The odb::transaction class has the following + interface:

 namespace odb
@@ -1346,7 +1613,9 @@ namespace odb
      has been finalized, (explicitly commited or rolled back),
      the destructor of the odb::transaction class will
      automatically roll it back when the transaction instance goes
-     out of scope.

+ out of scope. If you try to commit or roll back a finalized + transactions, the odb::transaction_already_finilized + is thrown.

The database() function returns the database this transaction is working on. The current() static @@ -1693,6 +1962,117 @@ db->erase<person> (jane_id); t.commit ();

+

3.7 ODB Exceptions

+ +

In the previous sections we have already mentioned some of the + exceptions that can be thrown by the database functions. In this + section we will discuss the ODB exception hierarchy and list + all the exceptions that can be thrown by the common ODB + runtime.

+ +

The root of the ODB exception hierarchy is the abstract + odb::exception class. This class inherits + from std::exception and has the following + interface:

+ +
+namespace odb
+{
+  struct exception: std::exception
+  {
+    virtual const char*
+    what () const throw () = 0;
+  };
+}
+  
+ +

Catching this exception guarantees that you will catch all + exceptions thrown by ODB. The what() function + returns a human-readable description of an exception.

+ +

The concrete exceptions that can be thrown by ODB are presented + in the following listing:

+ +
+namespace odb
+{
+  struct already_in_transaction: odb::exception
+  {
+    virtual const char*
+    what () const throw ();
+  };
+
+  struct not_in_transaction: odb::exception
+  {
+    virtual const char*
+    what () const throw ();
+  };
+
+  struct transaction_already_finilized: odb::exception
+  {
+    virtual const char*
+    what () const throw ();
+  };
+
+  struct deadlock: odb::exception
+  {
+    virtual const char*
+    what () const throw ();
+  };
+
+  struct object_not_persistent: odb::exception
+  {
+    virtual const char*
+    what () const throw ();
+  };
+
+  struct object_already_persistent: odb::exception
+  {
+    virtual const char*
+    what () const throw ();
+  };
+
+  struct database_exception: odb::exception
+  {
+  };
+}
+  
+ +

The first four exception (already_in_transaction, + not_in_transaction, + transaction_already_finilized, and + deadlock) are thrown by the + odb::transaction class and are discussed + in Section 3.3, "Transactions".

+ +

The object_already_persistent exception is thrown + by the persist() database function. See + Section 3.4, "Making Objects Persistent" + for details.

+ +

The object_not_persistent exception is thrown + by the load() and update() + database functions. Refer to + Section 3.5, "Loading Persistent Objects" and + Section 3.6, "Updating Persistent Objects" for + more information.

+ +

The database_exception is a base class for all + database system-specific exceptions that are thrown by the + database system-specific runtime library. See (@@ ref Chapter + Database Systems) for more information.

+ +

The odb::exception abstract base is defined in the + <odb/exception.hxx> header file. All the + concrete ODB exceptions are defined in + <odb/exceptions.hxx> which also includes + <odb/exception.hxx>. Normally you don't + need to include either of these two headers because they are + automatically included by <odb/database.hxx>. + However, if the source file that handles ODB exceptions + does not include <odb/database.hxx>, then + you will need to explicitly include one of these headers.

+ @@ -1709,7 +2089,7 @@ t.commit (); object oriented query language, called ODB query language. This query language is modeled after and is integrated into C++ allowing you to write expressive and safe queries that look and feel like - plain C++. We have already seen examples of these queries in the + ordinary C++. We have already seen examples of these queries in the introductory chapters. Below is another, more interesting, example:

-- 
cgit v1.1