0

I'm working on a pretty special, legacy project where I need to build an app for PDA devices under Windows Mobile 6.5. The devices have a local database (SQL Server CE) which we are supposed to sync with a remote database (Microsoft Access) whenever they are docked and have network access.

So the local database using SQL Server CE works fine, but I can’t figure out a way to sync it to the Access database properly.

I read that ODBC and OLEDB are unsupported under Windows Mobile 6.5, most ressources I find are obsolete or have empty links, and the only way I found was to export the local database relevant tables in XML in the hope to build a VBA component for Access to import them properly. (and figure out backwards sync).

Update on the project and new questions

First of all, thanks to everyone who provided an useful answer, and to @josef who saved me a lot of time with the auto path on this thread.

So a remote SQL Server is a no go for security reasons (client is paranoid about security and won't provide me a server). So I'm tied to SQL Server CE on the PDA and Access on the computer.

As for the sync:

  • The exportation is fine: I'm using multiple dataAdapters and a WriteXML method to generate XML files transmitted by FTP when the device is plugged back in. Those files are then automatically imported into the Access database. (see code at the end).

  • My problem is on the importation: I can acquire data through XML readers from an Access-generated file. This data is then inserted in a dataset (In fact, I can even print the data on the PDA screen) but I can't figure out a way to do an "UPSERT" on the PDA's database. So I need a creative way to update/insert the data to the tables if they already contains data with the same id.

I tried two methods, with SQL errors (from what I understood it's SQL Server CE doesn't handle stored procedures or T-SQL). Example with a simple query that is supposed to update the "available" flag of some storage spots:

try
{
    SqlCeDataAdapter dataAdapter = new SqlCeDataAdapter();
    DataSet xmlDataSet = new DataSet();
    xmlDataSet.ReadXml(localPath +@"\import.xml");

    dataGrid1.DataSource = xmlDataSet.Tables[1];

    _conn.Open();
    int i = 0;
    for (i = 0; i <= xmlDataSet.Tables[1].Rows.Count - 1; i++)
    {
        spot = xmlDataSet.Tables[1].Rows[i].ItemArray[0].ToString();
        is_available = Convert.ToBoolean(xmlDataSet.Tables[1].Rows[i].ItemArray[1]);

        SqlCeCommand importSpotCmd = new SqlCeCommand(@"
                    IF EXISTS (SELECT spot FROM spots WHERE spot=@spot) 
                    BEGIN
                        UPDATE spots SET available=@available
                    END
                    ELSE
                    BEGIN
                    INSERT INTO spots(spot, available) 
                        VALUES(@spot, @available)
                    END", _conn);
        importSpotCmd.Parameters.Add("@spot", spot);
        importSpotCmd.Parameters.Add("@available", is_available);

        dataAdapter.InsertCommand = importSpotCmd;
        dataAdapter.InsertCommand.ExecuteNonQuery();
    }
    _conn.Close();
}
catch (SqlCeException sql_ex)
{
    MessageBox.Show("SQL database error: " + sql_ex.Message);
}

I also tried this query, same problem SQL server ce apparently don't handle ON DUPLICATE KEY (I think it's MySQL specific).

INSERT INTO spots (spot, available) 
    VALUES(@spot, @available)
ON DUPLICATE KEY UPDATE spots SET available=@available

The code of the export method, fixed so it works fine but still relevant for anybody who wants to know:

    private void exportBtn_Click(object sender, EventArgs e)
    {

        const string sqlQuery = "SELECT * FROM storage";
        const string sqlQuery2 = "SELECT * FROM spots";
        string autoPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);  //get the current execution directory

        using (SqlCeConnection _conn = new SqlCeConnection(_connString))
        {
            try
            {
                SqlCeDataAdapter dataAdapter1 = new SqlCeDataAdapter(sqlQuery, _conn);
                SqlCeDataAdapter dataAdapter2 = new SqlCeDataAdapter(sqlQuery2, _conn);
                _conn.Open();
                DataSet ds = new DataSet("SQLExport");
                dataAdapter1.Fill(ds, "stock");
                dataAdapter2.Fill(ds, "spots");

                ds.WriteXml(autoPath + @"\export.xml");
            }
            catch (SqlCeException sql_ex)
            {
                MessageBox.Show("SQL database error: " + sql_ex.Message);
            }

        }
    }
Community
  • 1
  • 1
ChuckMaurice
  • 111
  • 7
  • 1
    Can you use linked table from MS Access into SQL (or maybe add MS Access as a linked server in a SQL Server instance?) and then use SQL CE RDA to sync the device with a remove SQL? Have a look at https://www.codeproject.com/Articles/5984/Pocket-PC-with-SQL-CE for an intro to RDA – KMoussa Apr 07 '17 at 13:39
  • I think you DataSet approach is a viable solution - the DataSet also has a WriteXml method! – ErikEJ Apr 07 '17 at 15:18
  • Windows Mobile 6.5? Suprised me that the question is not 5 years old. – Vojtěch Dohnal Apr 08 '17 at 05:36
  • I know, right? I'm struggling to get the necessary info on barely anything complicated (and I can't even debug properly due to lack of ActiceSync support), but, well, client specs... – ChuckMaurice Apr 10 '17 at 06:10

1 Answers1

2

As Access is more or less a stand-alone DB solution I strongly recommend to go with a full flavored SQL Server plus IIS to setup a Merge Replication synchronisation between the SQL CE data and the SQL Server data.

This is described with full sample code and setup in the book "Programming the .Net Compact Framework" by Paul Yao and David Durant (chapter 8, Synchronizing Mobile Data).

For a working sync, all changes to defined tables and data on the server and the CE device must be tracked (done via GUIDs, unique numbers) with there timestamps and a conflict handling has to be defined.

If the data is never changed by other means on the server, you may simply track Device side changes only and then push them to the Access database. This could be done by another app that does Buld Updates like described here.

If you do not want to go the expensive way to SQL Server, there are cheaper solutions with free SQLite (available for CE and Compact Framework too) and a commercial Sync tool for SQLite to MSAccess like DBSync.

If you are experienced, you may create your own SQLite to MS ACCESS sync tool.

Community
  • 1
  • 1
josef
  • 5,951
  • 1
  • 13
  • 24
  • I got the XML part (writing, file transfer and import) to work via secure FTP so I'm gonna focus for a few days on getting a SQL Server sync to work. My boss told me that she don't know if the client will allow us to install/use SQL Server (it's a pretty secure and closed environment), but if I can make a compelling point for it... XML was intended as a backup but it works so I'm ok on that. – ChuckMaurice Apr 11 '17 at 14:20
  • I tried to use SQLite on the Windows Mobile device but wasn't able to find any compatible solutions (deprecation, again...). SQL Server CE works great and my boss (which is designing the Access database) assured me that she could link Access to SQL Server tables. Also, data can be changed from the Access side too. So SQL Server/IIS seems that the best solution to me, assuming the client allows us to use it. – ChuckMaurice Apr 11 '17 at 14:22