July 23, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Using Database Engines in a Mobile Application

  • May 17, 2004
  • By Alex Gusev
  • Send Email »
  • More Articles »
Connecting to a data source

The first step you will do is connect to the desired data source. The ATL DB has a CDataSource class this purpose. The CSession class represents opened sessions. The following code sample shows all the required stuff:

HRESULT OpenDataSource()
{
   HRESULT hr;
   CDataSource db;
   CDBPropSet dbinit [2];

   dbinit [0].SetGUID(DBPROPSET_DBINIT);
   dbinit [1].SetGUID(DBPROPSET_SSCE_DBINIT);

   dbinit [0].AddProperty(DBPROP_INIT_DATASOURCE,         OLESTR
                         (<Path to database file>);
   dbinit [1].AddProperty(DBPROP_SSCE_TEMPFILE_DIRECTORY, OLESTR
                         (<Path to store temp files>);

   hr = db.Open(_T ("Microsoft.SQLSERVER.OLEDB.CE.2.0"), dbinit, 2);
   if (FAILED(hr))
   {
      return hr;
   }

   // m_session is of type CSession (refer to atldbcli.h for details)
   return m_session.Open(db);
}

You may add all desired DBPROP_INIT_XXX or DBPROP_SSCE_XXX propeties or implement additional wrapper classes if you need to. Once you've successfully opened the session, you should close it somewhere.

Start

ATL DB CE has several 'base' classes that handle a typical database's tasks. These classes are CCommand, CAccessor, CDynamicAccessor, and CRowset. CAccessor and CDynamicAccessor are used to fetch data. CAccessor does it by using fixed schema, while CDynamicAccessor allows you to do it all at runtime. In turn, the CRowset class precedes different data management operations such as inserting, deleting, and updating data in tables and working with cursors and bookmarks. The CCommand class, according to its name, executes commands by using assessors or row sets.

Now, taking all that was noted above in mind, we may start to code our simple ATL-based program. Let's start with executing some command. As we may find in atldbcli.h, the CCommand class has the following definition:

template <class TAccessor = CNoAccessor,
          class TRowset   = CRowset,
          class TMultiple = CNoMultipleResults>
class CCommand :
   public CAccessorRowset<TAccessor, TRowset>,
   public CCommandBase,
   public TMultiple

So, if you don't need any parameters or output columns, you may declare your command object as the following:

CCommand<CNoAccessor,CNoRowset> cmd;
HRESULT hr = cmd.Open(session, L"update GROUPS set name = 'group1'
                                 where code = 1");

That's the simplest way to run queries with INSERT, UPDATE, or DELETE statements. In the case of more complicated commands, you may first define, for example, fixed schema for data:

class CGroupsAccessor
{
   SHORT     m_nGroupCode;
   TCHAR     m_wszGroupDesc[14];

BEGIN_COLUMN_MAP(CGroupsAccessor)
   COLUMN_ENTRY(1, m_nGroupCode);
   COLUMN_ENTRY(2, m_wszGroupDesc);
END_COLUMN_MAP()

DEFINE_COMMAND (CGroupsAccessor, L"SELECT * FROM GROUPS")

   void ClearRecord()
   {
      memset(this, 0, sizeof(*this));
   }
};

Thus, we've declared the GROUPS table with two columns: code and description. In addition, the DEFINE_COMMAND macro defines a default SQL query to retrieve table data. Then, you are ready to declare a command object for each accessor:

CCommand<CAccessor<CGroupsAccessor> > cmd;
HRESULT hr = cmd.Open(session);

You also may use CDynamicAccessor instead of CAccessor-derived classes, as in the following example:

CCommand<CDynamicAccessor, CRowset> commandInsert;
TCHAR tszSQL[] = L"INSERT INTO GROUPS (Code,Name) VALUES (1,'Group1')";
hr = m_session.StartTransaction();
hr = commandInsert.Open(m_session,
                       (LPCTSTR) tszSQL,
                        NULL ,
                        NULL,
                        DBGUID_DBSQL,
                        false));
hr = m_session.Commit();

Now, several words about row sets. That is an alternative way to manipulate the data, like in ADOCE, with all the pro and contra. ATL DB CE doesn't support all kinds of CRowset-derived classes, but you will find CBulkRowset and CArrayRowset as useful examples. In addition, similarly to ADOCE, the CTable class handles database tables. The work flow for all of the above templates is to get the desired row set and then manage it by calling the corresponding Get/Set methods. Such an approach may be much more efficient because you're working directly with data without any SQL commands. On the other hand, the logic becomes more complicated. Hence, you should weigh both approaches before the final shot.

Where to go

As we saw, you have a lot of choices at hand. For me, the preferable way is to use ATL. If Microsoft will fix or re-port a desktop version of the ATL DB client, you'll get much more suitable classes than we have now under WinCE. I hope you're disoriented enough now to dive into the ATL DB consumer sea for the great fun. Good luck!

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.





Page 3 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel