From 18aeb349f502bfdf3ddc64e6a3f671a0a818a3f3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 1 Aug 2014 07:15:19 +0200 Subject: Add support for defining persistent objects as class template instantiations --- NEWS | 5 ++++ doc/manual.xhtml | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ odb/common.cxx | 4 +-- odb/common.hxx | 3 +- 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 576aad1..0dfd128 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,11 @@ Version 2.4.0 (translated to the ON DELETE SQL clause) for an object pointer. For more information, refer to Section 14.4.15, "on_delete" in the ODB manual. + * Support for defining persistent objects as instantiations of C++ class + templates, similar to composite value types. For details, refer to + Section 15.2, "Persistent Class Template Instantiations" in the ODB + manual. + * User-supplied prologues and epilogues are now generated outside the pre.hxx/post.hxx includes. This allows the use of precompiled headers with the generated files. diff --git a/doc/manual.xhtml b/doc/manual.xhtml index 06d7c82..57b95af 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -664,6 +664,7 @@ for consistency. 15Advanced Techniques and Mechanisms +
15.1Transaction Callbacks
15.2Persistent Class Template Instantiations
@@ -17931,6 +17932,93 @@ class object }; +

15.2 Persistent Class Template Instantiations

+ +

Similar to composite value types (Section 7.2, "Composite + Value Types"), a persistent object can be defined as an instantiation + of a C++ class template, for example:

+ +
+template <typename T>
+class person
+{
+  ...
+
+  T first_;
+  T last_;
+};
+
+typedef person<std::string> std_person;
+
+#pragma db object(std_person)
+#pragma db member(std_person::last_) id
+  
+ +

Note that the database support code for such a persistent object + is generated when compiling the header containing the + db object pragma and not the header containing + the template definition or the typedef name. This + allows us to use templates defined in other files, for example:

+ +
+#include <utility> // std::pair
+
+typedef std::pair<unsigned int, std::string> person;
+#pragma db object(person)
+#pragma db member(person::first) id auto column("id")
+#pragma db member(person::second) column("name")
+  
+ +

You may also have to explicitly specify the object type in + calls to certain database class functions due + to the inability do distinguish, at the API level, between + smart pointers and persistent objects defined as class + template instantiations. For example:

+ +
+person p;
+
+db.update (p); // Error.
+db.reload (p); // Error.
+db.erase (p);  // Error.
+
+db.update<person> (p); // Ok.
+db.reload<person> (p); // Ok.
+db.erase<person> (p);  // Ok.
+  
+ +

It also makes sense to factor persistent data members that do not + depend on template arguments into a common, non-template base class. + The following more realistic example illustrates this approach:

+ +
+#pragma db object abstract
+class base_common
+{
+  ...
+
+  #pragma db id auto
+  unsigned long id;
+};
+
+template <typename T>
+class base: public base_common
+{
+  ...
+
+  T value;
+};
+
+typedef base<std::string> string_base;
+#pragma db object(string_base) abstract
+
+#pragma db object
+class derived: public string_base
+{
+  ...
+};
+  
+ diff --git a/odb/common.cxx b/odb/common.cxx index f52cee6..b75d323 100644 --- a/odb/common.cxx +++ b/odb/common.cxx @@ -504,9 +504,9 @@ check (semantics::typedefs& t) if (ci == 0) return false; - // It must be a composite value. + // It must be an object or composite value. // - if (!composite (*ci)) + if (!object (*ci) && !composite (*ci)) return false; // This typedef name should be the one that was used in the pragma. diff --git a/odb/common.hxx b/odb/common.hxx index 0fcd481..6e70f43 100644 --- a/odb/common.hxx +++ b/odb/common.hxx @@ -420,7 +420,8 @@ private: columns columns_; }; -// Traverse composite values that are class template instantiations. +// Traverse objects and composite values that are class template +// instantiations. // struct typedefs: traversal::typedefs, context { -- cgit v1.1