Jan,
Thanks for the reply. It was not clear from my abridged example,
but I have the type_conversion classes defined. To make things more
concrete, here is a complete example that fails in the way my actual
code fails. I still feel I may be misunderstanding what I am supposed
to do here, so perhaps what I am trying to do does not make sense?
Anyway, here is an example:
///////////////////////////////
// orm.cc
// To compile (on my system)
// gcc orm.cc -o orm -I/usr/local/include/soci
-I/usr/include/postgresql -L/usr/local/lib -lsoci_core
-lsoci_postgresql -lpq -lstdc++
// Here is what the database tables look like
/************
CREATE TABLE object_id
(
id integer NOT NULL,
des text,
CONSTRAINT object_id_pkey PRIMARY KEY (id)
);
CREATE TABLE object_txt
(
id integer NOT NULL,
txt text,
CONSTRAINT object_txt_pkey PRIMARY KEY (id),
CONSTRAINT object_txt_id_fkey FOREIGN KEY (id)
REFERENCES object_id (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
INSERT INTO object_id(id, des) VALUES (1, 'One');
INSERT INTO object_id(id, des) VALUES (2, 'Two');
INSERT INTO object_id(id, des) VALUES (3, 'Three');
**************/
#include <string>
#include <soci/soci.h>
#include <soci/soci-postgresql.h>
struct Object
{
int id;
std::string txt;
Object() : id(0), txt("") {}
};
namespace soci
{
template<> struct type_conversion<Object>
{
typedef soci::values base_type;
static void from_base(soci::values const &v, soci::indicator ind, Object &f)
{
// Populate field values from database values
f.id = v.get<int>("id");
f.txt = v.get<std::string>("txt", "");
}
static void to_base(const Object &f, soci::values &v, soci::indicator &ind)
{
// Populate database values from field values
v.set("id", f.id);
v.set("txt", f.txt.size() ? f.txt : "");
ind = soci::i_ok;
}
};
}
Object Populate(Object &obj, int i)
{
obj.id = i+1;
obj.txt = (i==0) ? "Uno" : ((i==1) ? "Dos":"Tres");
return obj;
}
int main(int argc, char **argv)
{
soci::session sql(soci::postgresql, "dbname=soci_db password=xxx");
Object obj;
soci::statement st_put = (sql.prepare << "insert into object_txt(id,
txt) values (:id, :txt)", soci::use(obj));
for (int i=0; i < 3; i++) {
Populate(obj, i);
st_put.execute(true);
}
}
The error I am getting is:
prompt$ ./orm
terminate called after throwing an instance of 'soci::soci_error'
what(): ERROR: insert or update on table "object_txt" violates
foreign key constraint "object_txt_id_fkey"
DETAIL: Key (id)=(0) is not present in table "object_id".
Aborted
which suggests that something about the obj instance is not preserved
between the "use" and the "execute". The Populate() call is not needed
to make the example fail, one can inline it, but it is true to what I
had in my code. It does work, if I change the loop to:
for (int i=0; i < 3; i++) {
Populate(obj,i);
soci::statement st_put = (sql.prepare << "insert into
object_txt(id, txt) values (:id, :txt)", soci::use(obj));
st_put.execute(true);
}
but I wanted to optimize away the statement preparation. Any help on
this is appreciated.
Matt
On Wed, Jul 1, 2009 at 3:12 AM, Jan
Mikkelsen<[email protected]> wrote:
> Resending. Previous version was rejected(!) by the moderators for not
> coming from the subscribed address.
>
> Begin forwarded message:
>
>> From: "Jan Mikkelsen" <[email protected]>
>> Date: 1 July 2009 8:17:03 AM
>> To: "General-purpose list for SOCI users." <[email protected]
>> >
>> Subject: Re: [SOCI-users] Question about ORM
>>
>> Hi,
>>
>> You need to define how the type conversion works from your object to
>> the columns in your SQL. Something like the code below. If you
>> have a way of extracting the column names, their types and getting
>> access to methods for getting and setting the values you can
>> generalise this function.
>>
>> Regards,
>>
>> Jan Mikkelsen
>>
>> namespace soci {
>> template<> struct type_conversion<Object>
>> {
>> typedef values base_type;
>>
>> static void
>> from_base(
>> values const& v,
>> indicator /* ind */,
>> Object& o)
>> {
>> o.col1_setter(v.get<std::string>("col1", ""));
>> o.col2_setter(v.get<int>("col2"));
>> }
>>
>> static void
>> to_base(
>> Object const& o,
>> values& v,
>> indicator& ind)
>> {
>> std::string const& col1_val = o.col1_getter();
>> v.set("col1", col1_val, col1_val.is_empty() ? soci::i_null :
>> soci::i_ok);
>> v.set("col2", o.col2_getter());
>> ind = i_ok;
>> }
>> };
>> }
>>
>> ----- Original Message ----- From: "Matt Calder" <[email protected]>
>> To: "General-purpose list for SOCI users." <[email protected]
>> >
>> Sent: Wednesday, July 01, 2009 5:36 AM
>> Subject: [SOCI-users] Question about ORM
>>
>>
>>> Hi,
>>> I am having trouble with ORM. I have code like the following:
>>>
>>> // Function that fills object with values
>>> void FillObject(Object &obj, int i);
>>>
>>> // Start postgres session
>>> soci::session sql(soci::postgresql, ...);
>>>
>>> // Declare "use" object
>>> Object obj;
>>>
>>> // Prepare statement
>>> soci::statement st_put = (sql.prepare << "insert into tbl (col1,
>>> col2)
>>> values (:c1, :c2)", soci::use(obj));
>>>
>>> // Insert 10 objects into the database
>>> for (int i=0; i < 10; i++) {
>>> // Get the data for object i
>>> FillObject(obj, i);
>>>
>>> // Execute SQL
>>> st_put.execute(true); // <--- Throws exception due to bad foreign
>>> key (= 0)
>>>
>>> }
>>>
>>> The exception is thrown because the table I am inserting into has a
>>> foreign key constraint on (say) col1. The error message says the
>>> value
>>> I am putting into col1 is 0, but I can see using the debugger that
>>> the
>>> value in obj is not 0 and is OK. The ORM works for "Object"'s, if
>>> instead of the st_put.execute line I put the whole statement
>>> construction inside the loop, so I suspect I am violating the "object
>>> lifetime" restrictions but I don't see how. Is there anything
>>> obviously wrong with what I am doing here? I can flesh out the
>>> example
>>> more if that would help. Thanks,
>>>
>>> Matt
>>>
>>> ------------------------------------------------------------------------------
>>> _______________________________________________
>>> Soci-users mailing list
>>> [email protected]
>>> https://lists.sourceforge.net/lists/listinfo/soci-users
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Soci-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/soci-users
>
------------------------------------------------------------------------------
_______________________________________________
Soci-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/soci-users