views:

311

answers:

2

I have already setup syncing with Microsoft Sync Framework, and now I need to add fields to a table. How do I re-provision the databases?

The setup is exceedingly simple:

  • Two SQL Express 2008 servers
  • The scope includes the entire database
  • Using Microsoft Sync Framework 2.0
  • Synchronizing by direct access. Using the standard new SqlSyncProvider

Do I make the structural changes at both ends? Or do I only change one server and let Sync Framework somehow propagate the change?

Do I need to delete the _tracking tables and/or the stored procedures? How about the triggers?

Has anyone been using the Sync Framework? Please help.

+1  A: 

Actually, I posted my own answer on my blog http://myazurejourney.blogspot.com/

It has a few step, and it's definitely a hack. But it works.

check it out. tell me what you think

Rabbi
An important advantage to only re-provisioning the tables that you alter is that you keep all of the MetaData for the scope and all of the other tables participating in the scope
Rabbi
A: 

remove the scope and re-provision... use this code to remove a scope

private void RemoveScope(SqlConnection Conn, bool ShowAlert)
{
    foreach (var table in _settings.TablesToSync)
    {
        SqlCommand dropTracking = new SqlCommand(@"
            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_tracking]') AND type in (N'U'))
            DROP TABLE [dbo].[" + table.Key + "_tracking]", Conn);
        dropTracking.ExecuteNonQuery();

        SqlCommand dropTriggers = new SqlCommand(@"
            IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_delete_trigger]'))
            DROP TRIGGER [dbo].[" + table.Key + @"_delete_trigger];

            IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_insert_trigger]'))
            DROP TRIGGER [dbo].[" + table.Key + @"_insert_trigger];

            IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_update_trigger]'))
            DROP TRIGGER [dbo].[" + table.Key + @"_update_trigger];
        ", Conn);
        dropTriggers.ExecuteNonQuery();

        SqlCommand dropStoredProc = new SqlCommand(@"
            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_delete]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_delete];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_deletemetadata]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_deletemetadata];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_insert]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_insert];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_insertmetadata]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_insertmetadata];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_selectchanges]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_selectchanges];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_selectrow]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_selectrow];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_update]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_update];

            IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + table.Key + @"_updatemetadata]') AND type in (N'P', N'PC'))
            DROP PROCEDURE [dbo].[" + table.Key + @"_updatemetadata];
        ", Conn);
        dropStoredProc.ExecuteNonQuery();
    }

    SqlCommand getScopeGuid = new SqlCommand(@"
            USE [" + Conn.Database + @"]
            SELECT scope_config_id FROM scope_info WHERE scope_name = '" + _settings.ScopeName + "'", Conn);

    var reader = getScopeGuid.ExecuteReader();

    if (reader.HasRows)
    {
        reader.Read();

        var id = reader.GetGuid(0);

        reader.Close();

        SqlCommand deleteScope = new SqlCommand(@"
                DELETE FROM scope_info WHERE scope_config_id = '" + id + @"';
                DELETE FROM scope_config WHERE config_id = '" + id + @"';
            ", Conn);
        deleteScope.ExecuteNonQuery();
    }

    if(ShowAlert)
        MessageBox.Show("Scope has been removed");
}
Montago
B"HYup you've got the basic idea of how to totally get sync MetaData out of your database.First of all I want to point out to be careful. If you have multiple scopes pointing to the same tables. The code you presented will delete the triggers, sprocs, etc. shared between scopes and when you try to execute your other scope you'll be in trouble.I am surprised that a function like that is not included in the framework. Maybe as the "community" we can put together a utility that would include simple helper methods like this one and the one I posted on my blog.
Rabbi
Next I want to comment a bit on your programming:1. you use an anti-pattern of passing a parameter to show a message box. If the caller knows enough to pass that parameter then it should just be handling the UI on its own and just show the message box after this function returns.2. Conn is a funny choice for a parameter when you magically get the _settings object. I would think to do it the other way around if at all - settings should be the parameter (that is what you are working on) and Conn should be accessed through IOC or member variable.
Rabbi
3. Why "USE [" + Conn.Database + @"]"? If you are getting the name of the database from the connection. Then that must be the current database of the connection. So that is totally superfluous.
Rabbi
4. I would recommend that you execute the getScopeGuid and deletes as one command without the extra round-trip. Just use a TSQL variable (I have an example of that in my re-provision code that I posted on my blog). Or at the very least, you can use ExecuteScalar instead of all the piping code of opening and closing a reader.
Rabbi
1. MSFx version 2.1 includes a function to deprovision
Montago
2. i know im programming in an anti-pattern fashion, sorry about that.
Montago
3. the USE [Database] is a legacy from the SQL script... could/should be removed
Montago
4. Thanks for the tips.
Montago