diff options
-rw-r--r-- | doc/manual.xhtml | 270 |
1 files changed, 135 insertions, 135 deletions
diff --git a/doc/manual.xhtml b/doc/manual.xhtml index e8ee426..f49bed2 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -424,17 +424,17 @@ for consistency. data member. </li> <li>Provide clean and easy to use object-oriented persistence - model and database APIs that support development of realistic + model and database APIs that support the development of realistic applications for a wide variety of domains.</li> - <li>Provide portable and thread-safe implementation. ODB should be + <li>Provide a portable and thread-safe implementation. ODB should be written in standard C++ and capable of persisting any standard C++ classes.</li> <li>Provide profiles that integrate ODB with type systems of widely-used frameworks and libraries such as Qt and Boost.</li> - <li>Provide high-performance and low overhead implementation. ODB + <li>Provide a high-performance and low overhead implementation. ODB should make efficient use of database and application resources.</li> </ul> @@ -443,11 +443,11 @@ for consistency. <h2><a name="0.1">About This Document</a></h2> <p>The goal of this manual is to provide you with an understanding - of the object persistence model and APIs as implemented by ODB. + of the object persistence model and APIs which are implemented by ODB. 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 + this document. A basic understanding of relational database systems is advantageous but not expected or required.</p> @@ -495,13 +495,13 @@ for consistency. database schema, and run native SQL <code>SELECT</code> queries.</p> <p>ODB is not a framework. It does not dictate how you should write - your application. Rather it is designed to fit into your + 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 + from nor are there any restrictions on the data member types in persistent classes. Existing classes can be made persistent - with little or nor modifications.</p> + with a few or no modifications.</p> <p>ODB has been designed for high performance and low memory overhead. Prepared statements are used to send and receive @@ -514,26 +514,26 @@ for consistency. 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 + that each class must have nor are there per-object data structures allocated by ODB.</p> <p>In this chapter we present a high-level overview of ODB. We will start with the ODB architecture and then outline the workflow of building an application that uses ODB. We will - conclude this chapter by contrasting the drawbacks of + conclude the chapter by contrasting the drawbacks of the traditional way of saving C++ objects to relational databases with the benefits of using ODB for object - persistence. The next chapter takes the more hands-on approach + persistence. The next chapter takes a more hands-on approach and shows the concrete steps necessary to implement object persistence in a simple "Hello World" application.</p> <h2><a name="1.1">1.1 Architecture and Workflow</a></h2> <p>From the application developer's perspective, ODB - consist of three main components: the ODB compiler, the common + consists of three main components: the ODB compiler, the common runtime library, called <code>libodb</code>, and the database-specific runtime libraries, called - <code>libodb-<database></code> where <database> is + <code>libodb-<database></code>, where <database> is the name of the database system this runtime is for, for example, <code>libodb-mysql</code>. For instance, if the application is going to use the MySQL database for @@ -574,9 +574,9 @@ for consistency. the ODB Pragma Language and ODB Query Language. The ODB Pragma Language is used to communicate various properties of persistent classes to the ODB compiler by means of special <code>#pragma</code> - 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 + directives embedded in the C++ header files. It controls aspects + of the object-relational mapping such as names of tables and columns + that are used for persistent classes and their members or mapping between C++ types and database types.</p> <p>The ODB Query Language is an object-oriented database query @@ -596,7 +596,7 @@ for consistency. <h2><a name="1.2">1.2 Benefits</a></h2> <p>The traditional way of saving C++ objects to relational databases - requires manually writing code that converts between the database + requires that you manually write code which 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, @@ -607,16 +607,16 @@ for consistency. <li><b>Difficult and time consuming.</b> Writing database conversion code for any non-trivial application requires extensive knowledge of the specific database system and its APIs. - It can also take considerable amount of time to write + It can also take a considerable amount of time to write and maintain. Supporting multi-threaded applications can complicate this task even further.</li> <li><b>Suboptimal performance.</b> Optimal conversion often requires writing large amounts of extra code, such as parameter binding for prepared statements and caching - of connections, statements, and buffers. Writing such - code in an ad-hoc manner is often too difficult and time - consuming.</li> + of connections, statements, and buffers. Writing code + like this in an ad-hoc manner is often too difficult + and time consuming.</li> <li><b>Database vendor lock-in.</b> The conversion code is written for a specific database which makes it hard to switch to another @@ -637,7 +637,7 @@ for consistency. <ul class="list"> <li><b>Ease of use.</b> ODB automatically generates database conversion code from your C++ class declarations and allows you to manipulate - persistent objects using a simple and thread-safe object-oriented + persistent objects using simple and thread-safe object-oriented database APIs.</li> <li><b>Concise code.</b> With ODB hiding the details of the underlying @@ -648,7 +648,7 @@ for consistency. <li><b>Optimal performance.</b> ODB has been designed for high performance and low memory overhead. All the available optimization techniques, such as prepared statements and extensive connection, statement, - and buffer caching are used to provide the most efficient + and buffer caching, are used to provide the most efficient implementation for each database operation.</li> <li><b>Database portability.</b> Because the database conversion code @@ -671,7 +671,7 @@ for consistency. <p>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 + ORM implementations for C++ that still require you to write database conversion or member registration code for each persistent class, ODB keeps persistent classes purely declarative. The functional part, the database conversion @@ -810,10 +810,10 @@ private: by the database and assigned to the object when it is made persistent.</p> - <p>In this example we choose to add an identifier because none of + <p>In this example we chose to add an identifier because none of the existing members could serve the same purpose. However, if a class already has a member with suitable properties, then it - is natural to use that member for an identifier. For example, + is natural to use that member as an identifier. For example, if our <code>person</code> class contained some form of personal identification (SSN in the United States or ID/passport number in other countries), then we could use that as an id. Or, if @@ -851,15 +851,15 @@ class person <p>To compile the <code>person.hxx</code> header we created in the previous section and generate the support code for the MySQL - database we invoke the ODB compiler from a terminal (UNIX) or + database, we invoke the ODB compiler from a terminal (UNIX) or a command prompt (Windows):</p> <pre class="terminal"> odb -d mysql --generate-query person.hxx </pre> - <p>We will use MySQL as the database of choice in the reminder of - this chapter though other supported database systems can be used + <p>We will use MySQL as the database of choice in the remainder of + this chapter, though other supported database systems can be used instead.</p> <p>If you haven't installed the common ODB runtime library @@ -871,7 +871,7 @@ odb -d mysql --generate-query person.hxx person.hxx:10:24: fatal error: odb/core.hxx: No such file or directory </pre> - <p>To resolve this you will need to specify <code>libodb</code> headers + <p>To resolve this you will need to specify the <code>libodb</code> headers location with the <code>-I</code> preprocessor option, for example:</p> <pre class="terminal"> @@ -891,8 +891,8 @@ odb -I.../libodb -d mysql --generate-query person.hxx <code>person-odb.cxx</code> and link the resulting object file to your application.</p> - <p>You may be wondering what is the <code>--generate-query</code> - option for. It instructs the ODB compiler to generate + <p>You may be wondering what the <code>--generate-query</code> + option is for. It instructs the ODB compiler to generate optional query support code that we will use later in our "Hello World" example. Another option that we will find useful is <code>--generate-schema</code>. This option @@ -904,18 +904,18 @@ odb -I.../libodb -d mysql --generate-query person.hxx odb -d mysql --generate-query --generate-schema person.hxx </pre> - <p>The database schema file contains SQL statement that creates + <p>The database schema file contains SQL statements that creates tables necessary to store the persistent classes. We will learn how to use it in the next section.</p> - <p>If you would like to see the list of all the available ODB compiler + <p>If you would like to see a list of all the available ODB compiler options, refer to the <a href="http://www.codesynthesis.com/products/odb/doc/odb.xhtml">ODB Compiler Command Line Manual</a>.</p> <p>Now that we have the persistent class and the database support code, the only part that is left is the application code that - does something useful with all this. But before we move on to + does something useful with all of this. But before we move on to the fun part, let's first learn how to build and run an application that uses ODB. This way when we have some application code to try, there are no more delays before we can run it.</p> @@ -938,8 +938,8 @@ c++ -c person-odb.cxx </pre> <p>Similar to the ODB compilation, if you get an error stating that - a headers in <code>odb/</code> or <code>odb/mysql</code> directory - in not found, you will need to use the <code>-I</code> + a header in <code>odb/</code> or <code>odb/mysql</code> directory + is not found, you will need to use the <code>-I</code> preprocessor option to specify the location of the common ODB runtime library (<code>libodb</code>) and MySQL ODB runtime library (<code>libodb-mysql</code>).</p> @@ -967,10 +967,10 @@ c++ -o driver driver.o person-odb.o -lodb-mysql -lodb mysql --user=odb_test --database=odb_test < person.sql </pre> - <p>The above command will login to a local MySQL server as user - <code>odb_test</code> without a password and use database + <p>The above command will log in to a local MySQL server as user + <code>odb_test</code> without a password and use the database named <code>odb_test</code>. Note that after executing this - command all data stored in the <code>odb_test</code> database + command, all the data stored in the <code>odb_test</code> database will be deleted.</p> <p>Once the database schema is ready, we run our application @@ -1059,7 +1059,7 @@ main (int argc, char* argv[]) <p>Once we are in <code>main()</code>, the first thing we do is create the MySQL database object. Notice that this is the last line in <code>driver.cxx</code> that mentions MySQL explicitly; the rest - of the code works though the common interfaces and is database + of the code works through the common interfaces and is database system-independent. We use the <code>argc</code>/<code>argv</code> <code>mysql::database</code> constructor which automatically extract the database parameters, such as login name, password, @@ -1068,11 +1068,11 @@ main (int argc, char* argv[]) constructors which allow you to pass this information directly (see <a href="#6.1.2">Section 6.1.2, "MySQL Database Class"</a>).</p> - <p>Next we create three <code>person</code> objects. Right now they are + <p>Next, we create three <code>person</code> objects. Right now they are transient objects, which means that if we terminate the application at this point, they will be gone without any evidence of them ever existing. The next line starts a database transaction. We discuss - transactions in detail later in this manual. For now all we need + transactions in detail later in this manual. For now, all we need to know is that all ODB database operations must be performed within a transaction and that a transaction is an atomic unit of work; all database operations performed within a transaction either succeed @@ -1086,7 +1086,7 @@ main (int argc, char* argv[]) crashes at this point, there will still be no evidence of our objects ever existing.</p> - <p>In our case one more thing happens when we call <code>persist()</code>. + <p>In our case, one more thing happens when we call <code>persist()</code>. Remember that we decided to use database-assigned identifiers for our <code>person</code> objects. The call to <code>persist()</code> is where this assignment happens. Once this function returns, the @@ -1094,8 +1094,8 @@ main (int argc, char* argv[]) <p>After we have persisted our objects, it is time to commit the transaction and make the changes permanent. Only after the - <code>commit()</code> function returns successfully are we - guaranteed that the objects are made persistent. Continuing with + <code>commit()</code> function returns successfully, are we + guaranteed that the objects are made persistent. Continuing with the crash example, if our application terminates after the commit for whatever reason, the objects' state in the database will remain intact. In fact, as we will discover @@ -1104,15 +1104,15 @@ main (int argc, char* argv[]) transaction must be committed explicitly with the <code>commit()</code> call. If the <code>transaction</code> object leaves scope without the transaction being - explicitly committed or rolled back, it will be automatically + explicitly committed or rolled back, it will automatically be rolled back. This behavior allows you not to worry about exceptions being thrown within a transaction; if they cross the transaction boundary, the transaction will - be automatically rolled back and all the changes made + automatically be rolled back and all the changes made to the database undone.</p> <p>After the transaction has been committed, we save the - objects ids in local variables. We will use them later in this + objects' identifiers in local variables. We will use them later in this chapter to perform other database operations on our persistent objects. You might have noticed that our <code>person</code> class doesn't have the <code>id()</code> function that we use @@ -1138,7 +1138,7 @@ mysql --user=odb_test --database=odb_test < person.sql objects' state in the database. While we will make our application more entertaining shortly, for now we can use the <code>mysql</code> client to examine the database content. It will also give us a feel - for how the object are stored:</p> + for how the objects are stored:</p> <pre class="terminal"> mysql --user=odb_test --database=odb_test @@ -1227,7 +1227,7 @@ main (int argc, char* argv[]) <p>Then we begin a new transaction and call the <code>query()</code> database function. We pass a query expression (<code>query::age > 30</code>) which limits the returned objects - only to those with age greater than 30. We also save the result + only to those with the age greater than 30. We also save the result of the query in a local variable.</p> <p>The next few lines perform a standard for-loop iteration @@ -1244,7 +1244,7 @@ Hello, Jane! </pre> - <p>That looks about right but how do we know that the query actually + <p>That looks about right, but how do we know that the query actually used the database instead of just using some in-memory artifacts of the earlier <code>persist()</code> calls? One way to test this would be to comment out the first transaction in our application @@ -1288,8 +1288,8 @@ Hello, John (7)! Hello, Jane (8)! </pre> - <p>The identifiers 3, 6, and 9 that miss from the above list belong to - the "Joe Dirt" objects which are not selected by this query.</p> + <p>The identifiers 3, 6, and 9 that are missing from the above list belong + to the "Joe Dirt" objects which are not selected by this query.</p> <h2><a name="2.6">2.6 Updating Persistent Objects</a></h2> @@ -1376,8 +1376,8 @@ Hello, Joe! </pre> <p>What if we didn't have an identifier for Joe? Maybe this object - was made persisted in another run of our application or by another - application altogether. Provided that we have only one Joe Dirt + was made persistent in another run of our application or by another + application altogether. Provided that we only have one Joe Dirt in the database, we can use the query facility to come up with an alternative implementation of the above transaction:</p> @@ -1422,7 +1422,7 @@ Hello, Joe! <p>To delete John from the database we start a transaction, call the <code>erase()</code> database function with John's object - id, and commit the transaction. After the transaction is committed + id, and commit the transaction. After the transaction is committed, the erased object is no longer persistent.</p> <p>If we don't have an object id handy, we can use queries to find @@ -1485,7 +1485,7 @@ Hello, Joe! start with basic concepts and terminology in <a href="#3.1">Section 3.1</a> and continue with the discussion of the <code>odb::database</code> class in <a href="#3.2">Section 3.2</a> and transactions in - <a href="#3.3">Section 3.3</a>. The reminder of this chapter + <a href="#3.3">Section 3.3</a>. The remainder of this chapter deals with the core database operations and concludes with the discussion of ODB exceptions.</p> @@ -1500,9 +1500,9 @@ Hello, Joe! a software implementation for managing this data (for example MySQL), and, finally, some database software implementations may manage several data stores which are usually distinguished - by name. This name is also commonly referred to as database.</p> + by name. This name is also commonly referred to as a database.</p> - <p>In this manual, when we use just the word <em>database</em>, we + <p>In this manual, when we use the word <em>database</em>, we refer to the first meaning above, for example, "The <code>update()</code> function saves the object's state to the database." The term Database Management System (DBMS) is @@ -1538,22 +1538,22 @@ Hello, Joe! and <em>object class</em> interchangeably. In contrast, a value type can be a fundamental C++ type, such as <code>int</code> or a class type, such as <code>std::string</code>. - If a value consists of other values then is is called a + If a value consists of other values, then it is called a <em>composite value</em> and its type — a - <em>composite value type</em>. Otherwise the the value is + <em>composite value type</em>. Otherwise, the value is called <em>simple value</em> and its type — a <em>simple value type</em>. Note that the distinction between simple and composite values is conceptual rather than representational. For example, <code>std::string</code> is a simple value type because conceptually string is a single value even though the representation of the string - class may contain several data member each of which could be + class may contain several data members each of which could be considered a value. In fact, the same value type can be viewed (and mapped) as both simple and composite by different applications.</p> <p>Seeing how all these concepts map to the relational model - will hopefully make these distinctions more clear. In a relational + 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 to a single column while a composite value type is mapped to @@ -1567,8 +1567,8 @@ Hello, Joe! members: year, month, and day. In one application it can be considered a composite value and each member will get its own column in a relational database. In another application - it can considered a simple value and stored in a single - column as a number of day from some predefined date.</p> + it can be considered a simple value and stored in a single + column as a number of days from some predefined date.</p> <p>Until now, we have been using the term <em>persistent class</em> to refer to object classes. We will continue to do so even though @@ -1613,7 +1613,7 @@ Hello, Joe! the database-related properties of a class and its members (see <a href="#5">Chapter 5, "ODB Pragma Language"</a>).</p> - <p>You may be wondering whether we also have to do declare value types + <p>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 <code>int</code> or <code>std::string</code> since the ODB compiler knows how to map them to suitable database system types and @@ -1631,10 +1631,10 @@ Hello, Joe! a person, which is a real-world entity. Name and age, which we used as data members in our <code>person</code> class are clearly values. It is hard to think of age 31 or name "Joe" as having their - own identity.</p> + own identities.</p> <p>A good test to determine whether something is an object or - a value is to consider if other objects might reference + 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 @@ -1644,7 +1644,7 @@ Hello, Joe! 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 person's email address as an identifier.</p> + is to use a person's email address as an identifier.</p> <p>Note, however, that these are only guidelines. There could be good reasons to make something that would normally be @@ -1652,14 +1652,14 @@ Hello, Joe! stores a vast number of people. Many of the <code>person</code> 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 first name + affect the performance. In this case, we could make the first name and last name each an object and only store references to these objects in the <code>person</code> class.</p> <p>An instance of a persistent class can be in one of two states: <em>transient</em> and <em>persistent</em>. A transient instance only has a representation in the application's - memory and will cease to exist when the application terminates + 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 @@ -1706,7 +1706,7 @@ Hello, Joe! <p>The <code>odb::database</code> interface defines functions for starting transactions and manipulating persistent objects. - These are discussed in detail in the reminder of this chapter + These are discussed in detail in the remainder of this chapter as well as the next chapter which is dedicated to the topic of querying the database for persistent objects. For details on the system-specific <code>database</code> classes, refer to @@ -1740,7 +1740,7 @@ Hello, Joe! <p>By isolation we mean that the changes made to the database state during a transaction are only visible inside this transaction until and unless it is committed. Using the - above example with bank transfer, the results of the + above example with the bank transfer, the results of the debit operation performed on the first object is not visible to other transactions until the credit operation is successfully completed and the transaction is committed.</p> @@ -1792,7 +1792,7 @@ namespace odb back, the destructor of the <code>odb::transaction</code> class will automatically roll it back when the transaction instance goes out of scope. If you try to commit or roll back a finalized - transactions, the <code>odb::transaction_already_finalized</code> + transaction, the <code>odb::transaction_already_finalized</code> exception is thrown.</p> <p>The <code>database()</code> function returns the database this @@ -1803,7 +1803,7 @@ namespace odb You can check whether there is a transaction in effect in this thread using the <code>has_current()</code> static function.</p> - <p>If two or more transaction access or modify more than one object + <p>If two or more transactions access or modify more than one object and are executed concurrently by different applications or by different threads within the same application, then it is possible that these transactions will try to access objects in an incompatible @@ -1814,7 +1814,7 @@ namespace odb At the same time the second transaction has modified <code>object2</code> and is waiting for the first transaction to commit its changes to <code>object1</code> because it also needs to modify <code>object1</code>. - As a result none of the two transactions can complete.</p> + As a result, none of the two transactions can be completed.</p> <p>The database system detects such situations and automatically aborts the waiting operation in one of the deadlocked transactions. @@ -1842,14 +1842,14 @@ for (;;) </pre> <p>Note that in the above discussion of atomicity, consistency, - isolation, and durability, all of these guarantees only apply + isolation, and durability, all of those guarantees only apply to the object's state in the database as opposed to the object's state in the application's memory. It is possible to roll a transaction back but still have changes from this transaction in the application's memory. An easy way to avoid this potential inconsistency is to instantiate persistent objects only within the transaction scope. Consider, - for example, this two implementations of the same transaction:</p> + for example, these two implementations of the same transaction:</p> <pre class="c++"> void @@ -1887,7 +1887,7 @@ update_age (database& db, unsigned long id) <p>Of course, it may not always be possible to write the application in this style. Oftentimes we need to access and - modify application's state of persistent objects out of + modify the application's state of persistent objects out of transactions. In this case it may make sense to try to roll back the changes made to the application state if the transaction was rolled back and the database state @@ -1952,7 +1952,7 @@ update_age (database& db, person& p) number of objects persisted does not exceed the value space of the id type.</p> - <p>When calling the <code>persist()</code> functions we don't need to + <p>When calling the <code>persist()</code> functions, we don't need to explicitly specify the template type since it will be automatically deduced from the argument being passed. The <code>odb::object_traits</code> template used in the signature above is part of the database support @@ -2049,7 +2049,7 @@ t.commit (); find the object (or objects) matching some criteria (see <a href="#4">Chapter 4, "Querying the Database"</a>). Note, however, that loading an object's state using its - identifier can be significantly faster that executing a query.</p> + identifier can be significantly faster than executing a query.</p> <h2><a name="3.6">3.6 Updating Persistent Objects</a></h2> @@ -2167,7 +2167,7 @@ namespace odb } </pre> - <p>Catching this exception guarantees that you will catch all + <p>Catching this exception guarantees that you will catch all the exceptions thrown by ODB. The <code>what()</code> function returns a human-readable description of the condition that triggered the exception.</p> @@ -2226,7 +2226,7 @@ namespace odb } </pre> - <p>The first four exception (<code>already_in_transaction</code>, + <p>The first four exceptions (<code>already_in_transaction</code>, <code>not_in_transaction</code>, <code>transaction_already_finalized</code>, and <code>deadlock</code>) are thrown by the @@ -2277,7 +2277,7 @@ namespace odb explicitly request the generation of the necessary database support code with the <code>--generate-query</code> ODB compiler option.</p> - <p>ODB provides flexible query API that offers two distinct levels of + <p>ODB provides a flexible query API that offers two distinct levels of abstraction from the database system query language such as SQL. At the high level you are presented with an easy to use yet powerful object-oriented query language, called ODB Query Language. This @@ -2313,7 +2313,7 @@ namespace odb query q ("first = 'John' AND age = " + query::_ref (age)); </pre> - <p>Note that at this level you loose the static typing of + <p>Note that at this level you lose the static typing of query expressions. For example, if we wrote something like this:</p> <pre class="c++"> @@ -2331,7 +2331,7 @@ namespace odb </pre> <p>It would compile fine and would trigger an error only when executed - by the the database system.</p> + by the database system.</p> <p>You can also combine the two query languages in a single query, for example:</p> @@ -2343,10 +2343,10 @@ namespace odb <h2><a name="4.1">4.1 ODB Query Language</a></h2> - <p>An ODB query is an expression that tell the database system whether - any given object matches the desired criteria. As such a query expression - always evaluates to <code>true</code> or <code>false</code>. At - the higher lever, an expression consist of other expressions + <p>An ODB query is an expression that tells the database system whether + any given object matches the desired criteria. As such, a query expression + always evaluates as <code>true</code> or <code>false</code>. At + the higher level, an expression consists of other expressions combined with logical operators such as <code>&&</code> (AND), <code>||</code> (OR), and <code>!</code> (NOT). For example:</p> @@ -2439,10 +2439,10 @@ namespace odb </tr> </table> - <p>The <code>in()</code> function accepts maximum of five arguments. + <p>The <code>in()</code> function accepts a maximum of five arguments. Use the <code>in_range()</code> function if you need to compare to more than five values. This function accepts a pair of - standard C++ iterators and compares to all the value from + standard C++ iterators and compares to all the values from the <code>begin</code> position inclusive and until and excluding the <code>end</code> position. The following code fragment shows how we can use these functions:</p> @@ -2483,7 +2483,7 @@ namespace odb is copied from the C++ variable to the query instance at the query construction time. On the other hand, if a parameter is bound by reference, then the query instance stores a reference to the - bound variable. The actual value for the parameter is only extracted + bound variable. The actual value of the parameter is only extracted at the query execution time. Consider, for example, the following two queries:</p> @@ -2503,7 +2503,7 @@ namespace odb <code>_val()</code> and <code>_ref()</code>, that allow you to bind the parameter either by value or by reference, respectively. In the ODB query language, if the binding is not specified - explicitly, the value semantics is used by default. In the + explicitly, the value semantic is used by default. In the native query language, binding must always be specified explicitly. For example:</p> @@ -2519,7 +2519,7 @@ namespace odb <p>A query that only has by-value parameters does not depend on any other variables and is self-sufficient once constructed. A query - that has one or more by-reference parameter depends on the + that has one or more by-reference parameters depends on the bound variables until the query is executed. If one such variable goes out of scope and you execute the query, the behavior is undefined.</p> @@ -2541,16 +2541,16 @@ namespace odb query (const odb::query<T>&, bool cache = true); </pre> - <p>The first <code>query()</code> function is used to return all + <p>The first <code>query()</code> function is used to return all the persistent objects of a given type stored in the database. - The second functions uses the passed query instance to only return + The second function uses the passed query instance to only return objects matching the query criteria. The <code>cache</code> argument - determines whether the object states should be cached in the + determines whether the objects' states should be cached in the application's memory or if they should be returned by the database system one by one as the iteration over the result progresses. The result caching is discussed in detail in the next section.</p> - <p>When calling the <code>query()</code> function we have to + <p>When calling the <code>query()</code> function, we have to explicitly specify the object type we are querying. For example:</p> <pre class="c++"> @@ -2607,9 +2607,9 @@ result r (find_underage (db, query::first == "John")); make a copy of a result or assign one result to another, the two instances will refer to the same result stream. Advancing the current position in one instance will also advance it in - another. The result instance is only usable within a transaction + another. The result instance is only usable within the transaction it was created in. Trying to manipulate the result after the - transaction has terminates leads to undefined behavior.</p> + transaction has terminated leads to undefined behavior.</p> <p>The <code>odb::result</code> class template conforms to the standard C++ sequence requirements and has the following @@ -2665,7 +2665,7 @@ namespace odb cache the result at a later stage if it wasn't already cached during query execution.</p> - <p>If result is cached, the entire state of the returned + <p>If the result is cached, the database state of all the returned objects is stored in the application's memory. Note that the actual objects are still only instantiated on demand during result iteration. It is the raw database state that @@ -2673,7 +2673,7 @@ namespace odb the object's state is sent by the database system one object at a time as the iteration progresses.</p> - <p>Uncached results can improve performance of both the application + <p>Uncached results can improve the performance of both the application and the database system in situations where you have a large number of objects in the result or if you will only examine a small portion of the returned objects. However, uncached @@ -2681,7 +2681,7 @@ namespace odb uncached result in a transaction. Creating another result (cached or uncached) by calling <code>database::query()</code> will invalidate the existing uncached result. Furthermore, - executing any other database function, such as <code>update()</code> + calling any other database functions, such as <code>update()</code> or <code>erase()</code> will also invalidate the uncached result.</p> <p>The <code>empty()</code> function returns <code>true</code> if @@ -2766,8 +2766,8 @@ namespace odb <p>The overloaded <code>result_iterator::load()</code> functions are similar to <code>database::load()</code>. The first function returns a dynamically allocated instance of the current - object which you are responsible for deleting. As an optimization, - if the iterator already owns an object as a result of an earlier + object. As an optimization, if the iterator already owns an object + as a result of an earlier call to the <code>*</code> or <code>-></code> operator, then it relinquishes the ownership of this object and returns it instead. This allows you to write code like this without worrying about @@ -2816,7 +2816,7 @@ namespace odb language to capture database-specific information about C++ types. This chapter describes the ODB pragma language in more detail. It can be read together with other chapters in the manual to get a - sense of what kind configurations and mapping fine-tuning are + sense of what kind of configurations and mapping fine-tuning are possible. You can also use this chapter as a reference at a later stage.</p> @@ -2824,11 +2824,11 @@ namespace odb <p><code>#pragma db <i>qualifier</i> [<i>specifier</i> <i>specifier</i> ...]</code></p> - <p>The <em>qualifier</em> tell the ODB compiler what kind of C++ construct + <p>The <em>qualifier</em> tells the ODB compiler what kind of C++ construct this pragma describes. Valid qualifiers are <code>object</code>, <code>value</code>, and <code>member</code>. Pragmas with the <code>object</code> qualifier describe persistent object types. - It tells the ODB compiler that a C++ class it describe is a + It tells the ODB compiler that the C++ class it describes is a persistent class. Similarly, pragmas with the <code>value</code> qualifier describes value types and the <code>member</code> qualifier is used to describe data members of persistent object @@ -2836,7 +2836,7 @@ namespace odb <p>The <em>specifier</em> informs the ODB compiler about a particular database-related property of the C++ declaration. For example, the - <code>id</code> member specifier tell the ODB compiler that this + <code>id</code> member specifier tells the ODB compiler that this member contains this object's identifier. Below is the declaration of the <code>person</code> class that shows how we can use ODB pragmas:</p> @@ -2857,7 +2857,7 @@ private: data member the pragma belongs to. Rather, the pragma applies to a C++ declaration that immediately follows the pragma. Such pragmas are called <em>positioned pragmas</em>. In positioned pragmas that - apply to data members the <code>member</code> qualifier can be + apply to data members, the <code>member</code> qualifier can be omitted for brevity, for example:</p> <pre class="c++"> @@ -2947,7 +2947,7 @@ private: are several ways to deal with this problem. The easiest is to disable such warnings using one of the compiler-specific command line options or warning control pragmas. This method is described - in the following sub-section for most popular C++ compiler.</p> + in the following sub-section for popular C++ compilers.</p> <p>There are also several C++ compiler-independent methods that you can employ. The first is to use the <code>PRAGMA_DB</code> macro, @@ -2971,7 +2971,7 @@ private: }; </pre> - <p>The alternative to using the <code>PRAGMA_DB</code> macro is to + <p>An alternative to using the <code>PRAGMA_DB</code> macro is to group the <code>#pragma db</code> directives in blocks that are conditionally included into compilation only when compiled with the ODB compiler. For example:</p> @@ -2998,7 +2998,7 @@ private: <p>GNU g++ does not issue warnings about unknown pragmas unless requested with the <code>-Wall</code> command line option. - To disable only the unknown pragma warning you can add the + To disable only the unknown pragma warning, you can add the <code>-Wno-unknown-pragmas</code> option after <code>-Wall</code>, for example:</p> @@ -3010,7 +3010,7 @@ g++ -Wall -Wno-unknown-pragmas ... <p>Microsoft Visual C++ issues an unknown pragma warning (C4068) at warning level 1 or higher. This means that unless you have disabled - warnings altogether (level 0), you will see this warning.</p> + the warnings altogether (level 0), you will see this warning.</p> <p>To disable this warning via the compiler command line, you can add the <code>/wd4068</code> C++ compiler option in Visual Studio 2008 @@ -3018,7 +3018,7 @@ g++ -Wall -Wno-unknown-pragmas ... where you can enter warning numbers that should be disabled. Simply enter 4068 into this field.</p> - <p>You can also disable this warning only for a specific header or + <p>You can also disable this warning for only a specific header or a fragment of a header using the warning control pragma. For example:</p> @@ -3119,7 +3119,7 @@ private: <p>In the above example we changed the mapping for the <code>bool</code> type which is now mapped to the <code>INT</code> database type. In - this case the <code>value</code> pragma is all that is necessary + this case, the <code>value</code> pragma is all that is necessary since the ODB compiler will be able to figure out how to store a boolean value as an integer in the database. However, there could be situations where the ODB compiler will not know how to @@ -3131,7 +3131,7 @@ private: #pragma db value(bool) type("VARCHAR(5) NOT NULL") </pre> - <p>The possible database value for the C++ <code>true</code> value could + <p>The possible database values for the C++ <code>true</code> value could be <code>"true"</code>, or <code>"TRUE"</code>, or <code>"True"</code>. Or, maybe, all of the above are valid. The ODB compiler has no way of knowing how your application wants to convert <code>bool</code> @@ -3139,7 +3139,7 @@ private: ODB allows you to provide your own database conversion functions by specializing the <code>value_traits</code> class template. The <code>mapping</code> example in the <code>odb-examples</code> - package shows how to do this for all supported database systems.</p> + package shows how to do this for all the supported database systems.</p> <p>It is also possible to change the database type mapping for individual members, as described in <a href="#5.4">Section 5.4, "Data Member @@ -3234,7 +3234,7 @@ private: <p>Note that automatically-assigned object ids are not reused. If you have a high object turnover (that is, objects are routinely made persistent and then erased), then care must be taken not to - run out of object ids. In such situations using + run out of object ids. In such situations, using <code>unsigned long long</code> as the identifier type is a safe choice.</p> @@ -3261,9 +3261,9 @@ private: <p>The behavior of this specifier for members is similar to that for value types. The only difference is the scope. The value type pragma applies to all members with this value type that - don't have their own <code>type</code> specifiers. While the + don't have their own <code>type</code> specifiers, while the member pragma applies only to a single member. For more - information on the semantics of this specifier refer to + information on the semantics of this specifier, refer to <a href="#5.3">Section 5.3, "Value Type Pragmas"</a>.</p> <h3><a name="5.4.4">5.4.4 <code>column</code></a></h3> @@ -3428,7 +3428,7 @@ private: differently depending on whether the member of this type is an object id or not. If the member is an object id, then for this member <code>std::string</code> is mapped - to <code>VARCHAR(255) NOT NULL</code> MySQL type. Otherwise + to <code>VARCHAR(255) NOT NULL</code> MySQL type. Otherwise, it is mapped to <code>TEXT NOT NULL</code>.</p> <h3><a name="6.1.2">6.1.2 MySQL Database Class</a></h3> @@ -3534,7 +3534,7 @@ namespace odb <p>The overloaded <code>database</code> constructors allow you to specify MySQL database parameters that should be used when - connecting to the database. In MySQL <code>NULL</code> and + connecting to the database. In MySQL <code>NULL</code> and an empty string are treated as the same values for all the string parameters except <code>password</code> and <code>socket</code>. The <code>client_flags</code> argument @@ -3583,13 +3583,13 @@ namespace odb interface as well as the available implementations are described in the next section.</p> - <p>The set of accessor function following the constructors allows you + <p>The set of accessor functions following the constructors allow you to query the parameters of the <code>database</code> instance.</p> <p>The <code>connection()</code> function returns the MySQL database connection encapsulated by the <code>odb::mysql::connection</code> class. Normally, you wouldn't call this function directly and - instead let the ODB runtime manage database connections. However, + instead let the ODB runtime manage the database connections. However, if for some reason you need to access the underlying MySQL connection handle, refer to the MySQL ODB runtime source code for the interface of the <code>connection</code> class.</p> @@ -3634,7 +3634,7 @@ namespace odb <p>The <code>new_connection_factory</code> class creates a new connection whenever one is requested. When a connection is no - longer needed it is released and closed. The + longer needed, it is released and closed. The <code>connection_pool_factory</code> class implements a connection pool. It has the following interface:</p> @@ -3652,7 +3652,7 @@ namespace odb </pre> <p>The <code>max_connections</code> argument specifies the maximum - number of concurrent connections this pool factory will + number of concurrent connections that this pool factory will maintain. Similarly, the <code>min_connections</code> argument specifies the minimum number of available connections that should be kept open.</p> @@ -3663,7 +3663,7 @@ namespace odb <code>max_connections</code> value to see if a new connection can be created. If the total number of connections maintained by the pool is less than this value, then a new connection is - created and returned. Otherwise the calling thread is blocked + created and returned. Otherwise, the calling thread is blocked until a connection becomes available.</p> <p>When a connection is released, the pool factory first checks @@ -3671,16 +3671,16 @@ namespace odb one of them is unblocked and is given the connection. Otherwise, the pool factory checks whether the total number of connections maintained by the pool is greater than the <code>min_connections</code> - value. If that's the case, the connection is closed. Otherwise the + value. If that's the case, the connection is closed. Otherwise, the connection is added to the pool of available connections to be returned on the next request. In other words, if the number of connections maintained by the pool exceeds the <code>min_connections</code> number and there are no threads waiting for a new connection, then the pool will close the excess connections.</p> - <p>If <code>max_connections</code> value is 0 then the pool will + <p>If the <code>max_connections</code> value is 0, then the pool will create a new connection whenever all of the existing connections - are in use. If the <code>min_connections</code> value is 0 then + are in use. If the <code>min_connections</code> value is 0, then the pool will never close a connection and instead maintain all the connections that were ever created.</p> @@ -3751,13 +3751,13 @@ namespace odb a MySQL database operation fails. The MySQL-specific error information is accessible via the <code>error()</code>, <code>sqlstate()</code>, and <code>message()</code> functions. - All this information is also combined and returned in + All this information is also combined and returned in a human-readable form by the <code>what()</code> function.</p> <p>The <code>odb::mysql::cli_exception</code> is thrown by the command line parsing constructor of the <code>odb::mysql::database</code> class if the MySQL option values are missing or invalid. The - <code>what()</code> function provides human-readable description + <code>what()</code> function returns a human-readable description of an error.</p> </div> |