Overview
Features
Download
Documentation
Community
Add-Ons & Services

Mapping of complex data type with different statements?

A general discussion forum.

Mapping of complex data type with different statements?

Postby Soho » 22 Oct 2012, 10:29

For simplicity, suppose there is an collection of complex objects:
Code: Select all
struct data {
  int a;
  int b;
};
std::vector< data > data_collection;
//...
Poco::Data::Session db( "SQLite", ":memory:" );
Statement( db ) << "INSERT INTO TABLE_A VALUES( ?1 )", use( data_collection ), now; // should insert into TABLE_A values of data::a
Statement( db ) << "INSERT INTO TABLE_B VALUES( ?1 )", use( data_collection ), now; // should insert into TABLE_A values of data::b

To insert data::a into the TABLE_A i'm using specialization of the TypeHandler template:
Code: Select all
namespace Poco {
  namespace Data {

    template<>
    struct TypeHandler< data_collection::value_type > {
      typedef data_collection::value_type value_type;
      static std::size_t size() { return 1; }
      static void bind( std::size_t pos, const value_type& obj, AbstractBinder* pBinder ) {
        TypeHandler< int >::bind( pos++, obj.a, pBinder); // inserts data::a
      }
      static void prepare( std::size_t, const value_type&, AbstractPreparation* ) {}
      static void extract( std::size_t pos, value_type& obj, const value_type& defVal, AbstractExtractor* pExt ) {}
    };
  }
}

And now i have to insert data::b into the TABLE_B.
How can i do that since TypeHandler template is already specialized?
What is the best way to use the same data collection with different statements?

Thanks in advance :)
Soho
 
Posts: 6
Joined: 08 Sep 2012, 15:49

Re: Mapping of complex data type with different statements?

Postby alex » 23 Oct 2012, 21:59

Soho wrote:How can i do that since TypeHandler template is already specialized?
What is the best way to use the same data collection with different statements?

It's ugly and not thread safe, but you could have a static boolean in TypeHandler specialization to alternate between obj.a and obj.b. Still ugly, but if you do not need the data::a value after first insertion, you could set data::a to an invalid value during first visit to TypeHandler and that would be an indication to use data::b the next time. For a cleaner solution, you'll need an intermediary container for data::b.
alex
 
Posts: 1113
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Mapping of complex data type with different statements?

Postby Soho » 24 Oct 2012, 15:05

Thanks for reply,
alex wrote:It's ugly and not thread safe, but you could have a static boolean in TypeHandler specialization to alternate between obj.a and obj.b.

Inclining to similar solution but use pointer_to_functions/functors/delegates instead of boolean variable and switch them before each Statement(). Just cannot choose the best "poco way" - FunctionDelegate looks very heavy for that.
alex wrote:Still ugly, but if you do not need the data::a value after first insertion, you could set data::a to an invalid value during first visit to TypeHandler and that would be an indication to use data::b the next time.

Unfortunately, not applicable for my app - no values cannot be set manually.
alex wrote:For a cleaner solution, you'll need an intermediary container for data::b.

Really it is most clear solution. But we can see some overhead for that intermediate container. And it is too expensive for me.
Soho
 
Posts: 6
Joined: 08 Sep 2012, 15:49

Re: Mapping of complex data type with different statements?

Postby alex » 24 Oct 2012, 17:37

Soho wrote:Inclining to similar solution but use pointer_to_functions/functors/delegates instead of boolean variable and switch them before each Statement()

If you can afford it, an additional bool (or pointer) struct member looks like a clean and simple solution.
alex
 
Posts: 1113
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Mapping of complex data type with different statements?

Postby Soho » 18 Nov 2012, 18:55

With thanks to alex, current solution works, although it looks a little bit bulky. So, comments welcome!
Code: Select all
namespace Poco {
  namespace Data {

    typedef void ( *BindMethod )( std::size_t, const data_collection::value_type&, AbstractBinder* );
    typedef std::size_t ( *SizeMethod )();

    struct bind_context {
      SizeMethod sizeMethod;
      BindMethod bindMethod;
    };

    std::size_t size_of_a() { return FIELD_TABLE_A_LAST - 1; }
    std::size_t size_of_b() { return FIELD_TABLE_B_LAST - 1; }

    void bind_to_a( std::size_t, const data_collection::value_type& obj, AbstractBinder* pBinder ) {
      TypeHandler< int >::bind( pos++, obj.a, pBinder); // inserts data::a
    }

    void bind_to_b( std::size_t, const data_collection::value_type& obj, AbstractBinder* pBinder ) {
      TypeHandler< int >::bind( pos++, obj.b, pBinder); // inserts data::b
    }

    const bind_context CONTEXT_A = { size_of_a, bind_to_a };
    const bind_context CONTEXT_B = { size_of_b, bind_to_b };

    bind_context _bindContext = CONTEXT_A;

    void setContextA() { _bindContext = CONTEXT_A; }
    void setContextB() { _bindContext = CONTEXT_B; }

    template<>
    struct TypeHandler< data_collection::value_type > {
      typedef data_collection::value_type value_type;
      static std::size_t size() { return _bindContext.sizeMethod(); }
      static void bind( std::size_t pos, const value_type& obj, AbstractBinder* pBinder ) {
        _bindContext.bindMethod( pos, obj, pBinder ); // inserts data::a
      }
    };
  }
}

And using:
Code: Select all
...
  Poco::Data::setContextA();
  Statement( db ) << "INSERT INTO TABLE_A VALUES( ?1 )", use( data_collection ), now; // inserts values of data::a into TABLE_A
...
  Poco::Data::setContextB();
  Statement( db ) << "INSERT INTO TABLE_B VALUES( ?1 )", use( data_collection ), now; // inserts values of data::b into TABLE_B
...
Soho
 
Posts: 6
Joined: 08 Sep 2012, 15:49


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 1 guest

cron