Synchronize two SQL Server database using Dotmim sync framework - c#

I have a WinForms database driven application that I want to make it work in online/offline mode using Dotmim sync framework that I find an article by their author here.
The documentation for the library is here
this is my code to sync the two SQL Server databases one is localdb and the other one is now on the SQL Server Management Studio for the testing purpose:
string connect = #"Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=bright_square_db;Integrated Security=SSPI;AttachDBFilename=D:\Folder\project_file\bright_square_db.mdf";
string constring = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
SqlSyncProvider serverProvider = new SqlSyncProvider(constring);
SqlSyncProvider clientProvider = new SqlSyncProvider(connect);
SyncAgent agent = new SyncAgent(clientProvider, serverProvider, new string[] { "I have listed all the tables here" });
var progress = new SynchronousProgress<ProgressArgs>(s => MessageBox.Show($"{s.Context.SyncStage}:\t{s.Message}"));
var syncContext = await agent.SynchronizeAsync(progress);
MessageBox.Show(syncContext.ToString());
But, when I try to run the code. I am getting this error
The columns that indicated in the error are for a table that created by the sync process named "scope_info" inside the SQL Server database.

I have solved the problem by swapping the client and server connection string link in the third and fourth line of the above code. I don't know what exactly cause the problem, but lastly this changed makes the code work for me.

Related

SQL Server CE two way sync with remote Access database

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);
}
}
}
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.

How to Connect to SQL Server Programmatically in C#?

I have developed a program (C#) which creates a SQL database using this code:
string SQLCreation = "IF NOT EXISTS (SELECT * FROM master..sysdatabases WHERE Name = 'x') CREATE DATABASE x";
SqlConnection PublicSQLDBCreationConnection = new SqlConnection(connectionString);
SqlCommand PublicSQLDBCreation = new SqlCommand(SQLCreation, PublicSQLDBCreationConnection);
try
{
PublicSQLDBCreationConnection.Open();
PublicSQLDBCreation.ExecuteNonQuery();
PublicSQLDBCreationConnection.Close();
}
//'then creates a table and so on
Now I want to have a client application which connects to this database (via LAN) WITHOUT using IP or computer name. How is that possible? Is it possible do this and have a dataset while not mentioning IP Adr. or computer name?
P.S. Don't Worry Guys, I simplified my code just for your view, I have made sure that SQL injection or other attempts won't happen.
Also I have to say that My Reason for not mentioning servername or IP is that I want to mass deploy my Application on many Networks
You could use SqlDataSourceEnumerator to get a list of all Sql Servers that are visible and browsable. This is not a good technique, since you could get an instance that you don't have the right to create a database on it, but you could still try something with that.
var enumerator = SqlDataSourceEnumerator.Instance;
foreach (DataRow row in enumerator.GetDataSources().Rows)
{
var serverName = row["ServerName"];
var instance = row["InstanceName"];
// build a connection string and try to connect to it
}

What is the best way for me to connect to a offline database through C#

I have an application that needs to store loads of data in a table format. I want something easy to configure, which is also in built with C#.NET. I don't want to have to include additional DLL files.
Also some links to tutorials, explaining the connection process and querying would be great. I'm assuming this is just like PHP, but which database type do I need?
It needs to be able to hold a lot of data and the ability to perform backups would be nice.
I'm not sure what you mean by "built in with C#.NET", but SQL Server Express comes with Visual Studio.
If you're looking for "a self-contained, embeddable, zero-configuration SQL database engine", you could try System.Data.SQLite.
If you want an offline database you could use SQL Server CE, as its a in-process database that does not require being attached to a server instance, which is really what you want then. Here is an example in C# on how you would connect, and populate a data table to manipulate some data.
// this connectionstring can also be an absolute file path
string connectionString = "Data Source=|DataDirectory|\mydatabase.sdf";
using (SqlCeConnection connection = new SqlCeConnection(connectionString)) {
try {
connection.Open();
}
catch (SqlCeException) {
// connection failed
}
using (SqlCeDataAdapter adapter = new SqlCeDataAdapter("SELECT * FROM <table>", connection)) {
using (DataTable table = new DataTable("<table>")) {
adapter.Fill(); // Populate the table with your select statement
// do stuff with the datatable
// example:
foreach (DataRow row in table.Rows) {
row["mycolumn"] = "somedata";
}
table.AcceptChanges();
}
}
}
You can even use commands instead of data tables
using (SqlCeCommand command = new SqlCeCommand("DELETE FROM <table> WHERE id = '0'", connection)) {
command.ExecuteNonQuery(); // executes command
}
Have a look at the ease of SQL Server Compact
Not build-in but easily added, no install and free.

SQL Server SMO TransferData() runs slowly

I'm following http://www.mssqltips.com/tip.asp?tip=1910 and the following code actually does work, but takes about 90 seconds to run. The database schema has less than 10 (fairly straightforward) tables. I'm not sure why it takes so long. Any suggestions on how to debug this?
var host = "192.168...";
var user = "username";
var pass = "password";
var srcDbName = "srcDbName";
var dstDbName = "dstDbName";
var server = new Server(new ServerConnection(host, user, pass));
var srcDb = server.Databases[srcDbName];
var dstDb = new Database(server, dstDbName);
dstDb.Create();
var transfer = new Transfer(srcDb);
transfer.CopyAllTables = true;
transfer.Options.DriAll = true;
transfer.Options.ContinueScriptingOnError = false;
transfer.DestinationDatabase = dstDbName;
transfer.DestinationServer = server.Name;
transfer.DestinationLoginSecure = false;
transfer.DestinationLogin = user;
transfer.DestinationPassword = pass;
transfer.TransferData();
I think that you should leave this code alone. You cannot improve it. AS I understand from the question you want to transfer tables/schema from one database to other .
Below options that I suggest :
Linked Servers
From SQL 2000 you should be able to connect directly to other database as a linked server. In the pros column this kind of direct access can be easy to work with if you don't have any other technical skills such as DTS or SSIS, but it can be complex to get the initial set-up right and there may be security concerns/issues.
DTS
DTS is packaged with SQL 2000 and is made for this kind of a task. If written correctly, your DTS package can have good error-handling and be rerunnable/reusable.
SSIS
SSIS is actually packaged with SQL 2005 and above, but you can connect it to other databases. It's basically a better version of DTS.

C#: DB2 test available connection first

I have a C# .NET program running an ETL which connects to a DB2 database. Sometimes this database is down, so I'd like to do a health check at the beginning of the application to see if the database is available, without actually calling any stored procedures or pushing any data. Here's an example of the code I'm using now:
OdbcConnection myODBCConnection = new OdbcConnection("DSN=DB2AA;UID=ABCD;PWD=1234;");
OdbcCommand myODBCCommand = new OdbcCommand();
myODBCCommand.CommandType = CommandType.StoredProcedure;
myODBCCommand.CommandText = "{CALL SYSPROC.ABC001(?, ?)}";
myODBCCommand.Parameters.Add("INPUT", OdbcType.VarChar, 500);
myODBCCommand.Parameters["INPUT"] = myString
myODBCCommand.Connection = myODBCConnection
myODBCConnection.Open();
OdbcTransaction myTrans;
myTrans = myODBCConnection.BeginTransaction();
myODBCCommand.Transaction = myTrans;
myTrans.Commit();
myODBCCommand.ExecuteNonQuery();
myODBCConnection.Close();
What's the best way to test this connection without actually pushing any data?
You can simply run some innoccuous select query to check to see if the db is available.
You can try to do something as simple as:
Select 1
Or
Select getdate()
Those simple queries don't even touch any tables but will return only if the rdbms is running.
Note: those examples are for sql server but might work for db2. I haven't had to do a live check on a db2 yet though the similar concept should be doable.
Note 2: after a closer look at your code, all you should really have/need to do is check for success of your odbc connection's .Open() call.

Categories