2

좋은 날 모두, 내가 아는ASP.NET 2.0, SQL Server Express에 2008 동기화 프레임 워크 1.0 C# 간단한 시나리오 예

, 내가 얘기하고있는 버전이 지금 쯤은 오히려 사용되지 않는하지만 난에 붙어있는 도구입니다 직장에서 일하십시오. 이것은 StackOverflow에 대한 나의 첫 번째 질문이며, 나는 형식화 권리를 얻으려고 희망한다 ;-) 긴 텍스트를 위해 나를 용서 해주고, 나는 많은 세부 사항을주고 익숙해 져있다.

IT 분야에서 일하는 거의 10 년 동안 나는 잘 선택된 키워드와 표현을 인터넷 검색하여 내 질문에 대한 해결책을 찾을 수있었습니다. 앞서 언급 한 Sync Framework가 인터넷 커뮤니티에 잘 알려지지 않은 것처럼 보입니다. 그렇지 않으면 대부분의 필사자에게 가장 단순한 개념을 이해하는 것이 정말 고통 스럽습니다. 광범위한 연구 끝에 Sync Framework 1.0과 C# 언어를 사용하여 SQL Express를 동기화하는 단일 예제를 발견해야합니다 (MSDN은 아님)! 나는 ASP.NET/C#에 상당히 익숙하지만 개념을 이해하고 SQL Server 2008 데이터베이스에서 데이터를 성공적으로 저장하고 검색하는 작업 웹 응용 프로그램이 있습니다. 그것은 2 년 동안 고객에 의해 지금 사용되어 왔습니다. 이제 클라이언트가 데이터를 오프라인으로 가져와 오프라인으로 업데이트 한 다음 서버와 동기화 할 수 있어야합니다. 두 끝에서 UPDATE, INSERT 및 DELETE가 발생합니다.

내가 찾고자하는 것은 매우 간단하다 (또는 그렇게 생각했다.) SQL Server 변경 추적 정보 (사용자 지정 변경 추적 아님)를 사용하는 C# 코드 예제는 서버 (SQL Server 2008)와 클라이언트 컴퓨터 (SQL 서버 2008 익스프레스, 컴팩트 에디션). 가장 간단한 경우는 컬럼이 거의없는 단일 테이블입니다. SQL Server 부분을 이해하고 클라이언트 웹 응용 프로그램에서 동기화 요청을 받도록 데이터베이스 양쪽을 준비했습니다 (변경 추적 사용, PrimaryKeyID에 데이터 형식 GUID, 서버의 응용 프로그램 사용자 계정에 VIEW_CHANGE_TRACKING 권한이 있음). 등등)

나는이 둘 사이의 인터페이스 역할을하는 동기화 애플리케이션 (C#)을 관리하는 웹 애플리케이션이라는 것을 알고있다. 남은 유일한 일은 두 개의 연결 문자열을 제공하고 어떤 테이블을 동기화할지 알려주고 양방향 동기화를 지정하는 것입니다. 분명히, 그것은 hehe보다 더 복잡합니다. 절망적 인 시도로 필자는 Microsoft의 다음 코드를 기반으로 SQL Express (이 예제는 Compact 용)에 적용하려고 시도했습니다. 나는 패배를 인정하고 부끄럽게 상기 내용을 토대로

http://msdn.microsoft.com/en-us/library/bb726015%28v=sql.100%29.aspx

:-(내 머리를 낮추기 위해 가까운 오전, 내가 필요하지 않은 모든 것을 제거 (두 번째 섹션 "SQL 서버 변경 내용 추적을 사용하여 완벽한 예") : 일을 SSMS에서 스크립트를 실행하는 SQL Server 자체에서 수동으로 변경 사항을 적용했습니다. (그리고 따라서 생성 된 변경 추적 정보와 웹 앱이 동기화를 요청할 때 사용할 수있는 변경 추적 정보가 있어야합니다.) 질문 1 : 내가 잘못 말하고 있습니까? 마지막으로 SQL Express와 관련된 객체를 사용하기 위해 일부 정보를 변경했습니다. 컴팩트 대신

질문 2 : Microsoft의 코드는이 복제본의 초기 (첫 번째) 또는 후속 동기화인지 여부를 분명히 알 수 있습니다. 나는 그것이 어떻게 할 수 있는지 모른다!

결국 간단한 형태로 남아있는 코드는 다음과 같습니다 (질문 3, 4, 5 ;-)로 표시되지만 오류가 있음). 도와 주셔서 미리 감사드립니다. 모든 의견 및/또는 제안을 환영합니다. 이 문제가 해결되면 꽤 많은 사람들에게 도움이 될 것입니다. 나는 그것을 끝까지 연구 할 것입니다. (상사가 나에게 선택권을주지 않을 것입니다. ;-) 나는 동기화에 성공한다면 여기에 해결책을 게시하겠다고 약속합니다!

감사합니다. 멋진 하루 되세요!

친절한 안부를

Zyxy

using System; 
using System.Collections; 
using System.Configuration; 
using System.Data; 
using System.Data.SqlClient; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Web; 
using System.Web.Security; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.Web.UI.WebControls.WebParts; 
using System.Web.UI.HtmlControls; 

using System.IO; 
//using System.Data.SqlServerCe; 
using Microsoft.Synchronization; 
using Microsoft.Synchronization.Data; 
using Microsoft.Synchronization.Data.Server; 
//using Microsoft.Synchronization.Data.SqlServerCe; 

namespace some_namespace 
{ 
public class SyncProgram 
{ 
    public SyncProgram() 
    { 
      // empty constructor 
    } 

    public static bool MainSync() // Entry point, say, called by a Sync button on an ASPX page. 
    { 
     bool boolSyncRes = false; // tells whether sync was a success or not 

     // Initial sync: they create a new instance of the Orchestrator. 
     ZyxySyncOrchestrator zyxySyncOrchestrator = new ZyxySyncOrchestrator(); 

     // Subsequent synchronization. 
     // They don't. there was only irrelevant stats stuff here. 

     boolSyncRes = true; 
     return boolSyncRes; 

      } 
} 

public class ZyxySyncOrchestrator : SyncOrchestrator 
{ 
    public ZyxySyncOrchestrator() 
    { 
     Utility util = new Utility(); 

     this.LocalProvider = new ZyxyServerSyncProvider(); // QUESTION 3: ??? cannot implicitly convert type DbServerSyncProvider to Microsoft.Synchronization.SyncProvider 

     //Instantiate a server synchronization provider and specify it 
     //as the remote provider for this synchronization agent. 
     this.RemoteProvider = new ZyxyServerSyncProvider(); // cannot implicitly convert type DbServerSyncProvider to Microsoft.Synchronization.SyncProvider 

     // QUESTION 4: Is the following code actually creating the base (user) table ZyxySync 
     // (as opposed to its change tracking metadata table)?? 
     // I wasn't sure whether this part of the code on Microsoft's webpage was part of 
     // populating the db with sample data and structure or if it's really meant to deal with 
     // the change tracking metadata. 
     SyncTable zyxySyncTable = new SyncTable("ZyxySync"); 
     zyxySyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable; 
     zyxySyncTable.SyncDirection = SyncDirection.DownloadOnly; 
     this.Configuration.SyncTables.Add(zyxySyncTable); 

    } 
} 

//Create a class that is derived from Microsoft.Synchronization.Server.DbServerSyncProvider. 
public class ZyxyServerSyncProvider : DbServerSyncProvider 
{ 
    public ZyxyServerSyncProvider() 
    { 
     Utility util = new Utility(); 
     SqlConnection serverConn = new SqlConnection(util.ServerConnString); 
     this.Connection = serverConn; 

     //Retrieve a new anchor value from the server. We use a timestamp value 
     //that is retrieved and stored in the client database. 
     //During each sync the new and last anchor values are used to determine the set of changes 
     SqlCommand selectNewAnchorCommand = new SqlCommand(); 
     string newAnchorVariable = "@" + SyncSession.SyncNewReceivedAnchor; 
     selectNewAnchorCommand.CommandText = 
      "SELECT " + newAnchorVariable + " = change_tracking_current_version()"; 
     selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.BigInt); 
     selectNewAnchorCommand.Parameters[newAnchorVariable].Direction = ParameterDirection.Output; 
     selectNewAnchorCommand.Connection = serverConn; 
     this.SelectNewAnchorCommand = selectNewAnchorCommand; 


     //Create a SyncAdapter for the ZyxySync table by using 
     //the SqlSyncAdapterBuilder. 
     // Specify a name for the SyncAdapter that matches the 
     // the name specified for the corresponding SyncTable. 
      SqlSyncAdapterBuilder zyxyBuilder = new SqlSyncAdapterBuilder(serverConn); 

     zyxyBuilder.TableName = "dbo.ZyxySync"; 
     zyxyBuilder.ChangeTrackingType = ChangeTrackingType.SqlServerChangeTracking; 

     SyncAdapter zyxySyncAdapter = zyxyBuilder.ToSyncAdapter(); 
     zyxySyncAdapter.TableName = "ZyxySync"; 
     this.SyncAdapters.Add(zyxySyncAdapter); 

    } 
} 

    // Class derived from Microsoft.Synchronization.Data.Server.DbServerSyncProvider 
// QUESTION 5: Or should have I used the two below? I believe they only apply to SQL Compact... 
//Microsoft.Synchronization.Data.ClientSyncProvider 
//Microsoft.Synchronization.Data.ServerSyncProvider 
//http://msdn.microsoft.com/en-us/library/microsoft.synchronization.data.clientsyncprovider%28v=sql.100%29.aspx 
//http://msdn.microsoft.com/en-us/library/microsoft.synchronization.data.server.dbserversyncprovider%28d=printer,v=sql.100%29.aspx 

public class ZyxyClientSyncProvider : DbServerSyncProvider 
{ 

    public ZyxyClientSyncProvider() 
    { 
     Utility util = new Utility(); 
     SqlConnection clientConn = new SqlConnection(util.ClientConnString); 
     this.Connection = clientConn; 
    } 
} 

public class Utility 
{ 
    public string ClientConnString 
    { 
     get { return @"Data Source=localhost\LocalExpressInstance;Initial Catalog=DatabaseName;User ID=UserName;Password=WontTellYou;"; } 
    } 

    public string ServerConnString 
    { 
      get { return @" Data Source=ServerName\ServerInstance;Initial Catalog=DatabaseName;User ID=UserName;Password=WontTellYou;"; } 
    } 
} 

}

+0

: 코드의 자동 형식의 색상이 모든 잘못! Hehe 그것에 대해 미안 해요, StackOverflow에 내 첫 게시물이야 ;-) – Zyxy

답변

1

SyncOrchestrator가 DBServerSyncProvider 작동하지 않습니다.

Sync Framework에는 오프라인 공급자와 피어 - 투 - 피어/공동 작업 공급자의 두 가지 유형의 데이터베이스 공급자가 있습니다. (둘 다 오프라인 시나리오에서 작동하므로 혼란 스럽습니다).

오프라인 공급자는 허브 스포크 토폴로지에 사용됩니다. 클라이언트 만 동기화 된 항목을 추적합니다. 서버는 동기화의 일부를 알지도 못합니다. 이것은 Visual Studio의 로컬 데이터베이스 캐시 프로젝트 항목에서 사용하는 것과 동일한 공급자입니다. 즉시 지원되는 유일한 데이터베이스는 SqlCeClientSyncProvider 및 DBServerSyncProvider이며 SyncAgent를 사용하여 동기화합니다.

피어 투 피어 공급자는 hub-spoke 시나리오뿐만 아니라 피어 - 투 - 피어 동기화에서 사용할 수 있습니다. 각 피어는 동기화 된 항목에 대한 메타 데이터를 유지 관리합니다. 이것은 훨씬 새로운 SyncOrchestrator/SqlCeSyncProvider/SqlSyncProvider (SQL Server, Express, LocalDB 및 SQL Azure에서 작동)를 사용합니다. 이것은 사용자 지정 변경 내용 추적을 사용합니다.

SyncAgent 및 SyncOrchestrator에서 사용하는 공급자를 교환 할 수 없습니다. 추적, 선택, 변경 적용 및 동기화 대상 기록 방식이 다르므로 SQL 명령을 재사용 할 수 없습니다.

+0

대단히 감사합니다 JuneT! 당신은 내가 혼란스러워했던 몇 가지 점을 분명히했습니다. 네, SF를 처음 접했을 때 약간 혼란 스럽습니다. 당신은 인상적인 이력서 (CV)를 가지고 있으며 웹 (.NET 포럼, StackOverflow 등) 전체에서 답변을드립니다. 축하합니다! 나는 내 클라이언트와 서버를 성공적으로 동기화하여 코드 샘플이 다른 사람을 이해하는 데 도움이 될 수 있도록 여기에 게시 할 예정입니다 ... 감사합니다 !! – Zyxy

1

괜찮 았던 것 같아요. 그래서 여기서는 (어쨌든) 제 간단한 코드 샘플이 작동합니다. 위의 단계 (변경 추적 사용, 올바른 사용자 권한 설정 등) 외에도 다음 내용이 이해되지 않았습니다.

1) Sync Framework 동기화 세션은 모두 클라이언트 측에서 관리됩니다. 서버에 설치되어있는 것에 의존하지 않고, 이전 1.0 대신 SF 2.1을 사용할 수있었습니다. 그것은 많은 도움이되었습니다.

2) 동기화 세션을 준비 할 때 먼저 동기화 준비가되도록 데이터베이스를 프로비저닝해야합니다. 내가 한 것은 다음과 같은 C#을 클라이언트 연결 문자열로 실행하여 클라이언트 db를 프로비저닝 한 다음 서버 연결 문자열로 다시 실행하여 서버 db를 프로비저닝하도록하는 것입니다. 이것은 DB를 준비하기 위해 한 번 실행되는 프로그램입니다 (양쪽에서). 설정 한 모든 동기화 세션마다 실행하지 마십시오.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.Collections; 
using System.Configuration; 
using System.Data; 
using System.Data.SqlClient; 
using System.Text.RegularExpressions; 
using System.Security.Principal; 
using System.IO; 

using Microsoft.Synchronization; 
using Microsoft.Synchronization.Data; 
using Microsoft.Synchronization.Data.Server; 
using Microsoft.Synchronization.Data.SqlServer; // SF 2.1 
using Microsoft.Synchronization.SimpleProviders; // SF 2.1 
using Microsoft.Synchronization.MetadataStorage; // SF 2.1 

// ZYXY: Based on: 
// http://msdn.microsoft.com/en-us/library/ff928603.aspx 
// NOTES: 
// - Microsoft Sync Framework 2.1 redistributable package must be installed on Client computers but is not required on the Server, as long as a server-side synchronization setup is performed by a client computer. 
// This is a run once program. 

namespace DISS_Database_Sync_Provisioning_Console 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 


     SqlConnection sqlConn = new SqlConnection("Data Source=ServerName\\InstanceName;Initial Catalog=SomeDatabase;User ID=SOmeUser;Password=SomePassword;"); 

    Console.Write("Provisioning database..."); 



     // define a new scope named DISS_Sync_Scope 
     DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription("DISS_Sync_Scope"); 

     // get the description of the ZyxySync table 
     DbSyncTableDescription tableDesc = SqlSyncDescriptionBuilder.GetDescriptionForTable("dbo.ZyxySync", sqlConn); 

     // add the table description to the sync scope definition 
     scopeDesc.Tables.Add(tableDesc); 

     // create a server scope provisioning object based on the DISS_Sync_Scope 
     SqlSyncScopeProvisioning sqlProvision = new SqlSyncScopeProvisioning(sqlConn, scopeDesc); 

     // skipping the creation of base table since table already exists 
     sqlProvision.SetCreateTableDefault(DbSyncCreationOption.Skip); 

     // start the provisioning process 
     sqlProvision.Apply(); 

     sqlConn.Close(); 
     sqlConn.Dispose(); 

     Console.Write("\nDatabase has been successfully configured for synchronization. Please press any key to exit."); 
     Console.Read(); 

    } 
} 
} 

3) 다음은 매번 실행되는 동기화 (실행되는 코드입니다 예를 들어, 사용자가 자신의 웹 응용 프로그램에서 자신의 "동기화"버튼을 클릭합니다.)

using System; 
using System.Collections; 
using System.Configuration; 
using System.Data; 
using System.Data.SqlClient; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Web; 
using System.Web.Security; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.Web.UI.WebControls.WebParts; 
using System.Web.UI.HtmlControls; 

using System.Security.Principal; 

using System.IO; 
using Microsoft.Synchronization; 
using Microsoft.Synchronization.Data; 
using Microsoft.Synchronization.Data.Server; 
using Microsoft.Synchronization.Data.SqlServer; // SF 2.1 
using Microsoft.Synchronization.SimpleProviders; // SF 2.1 
using Microsoft.Synchronization.MetadataStorage; // SF 2.1 

namespace diss_ssmb 
{ 



public class SyncProgram 
{ 


    public SyncProgram() 
    { 
      // empty constructor 
    } 

    public static bool MainSync() // Entry point, say, called by a Sync button on an ASPX page. 
    { 
     bool boolSyncRes = false; // tells whether sync was a success or not 

     // Initial sync: they create a new instance of the Orchestrator. 
     ZyxySyncOrchestrator zyxySyncOrchestrator = new ZyxySyncOrchestrator(); 

     // Subsequent synchronization. 
     // They don't. there was only irrelevant stats stuff here. 

     boolSyncRes = true; 
     return boolSyncRes; 

      } 
} 

public class ZyxySyncOrchestrator : SyncOrchestrator 
{ 
    public ZyxySyncOrchestrator() 
    { 
     Utility util = new Utility(); 


     this.LocalProvider = new ZyxyClientSyncProvider(); 

     //Instantiate a server synchronization provider and specify it 
     //as the remote provider for this synchronization agent. 
     this.RemoteProvider = new ZyxyServerSyncProvider(); 

     SyncTable zyxySyncTable = new SyncTable("ZyxySync"); 
     zyxySyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable; 
     zyxySyncTable.SyncDirection = SyncDirection.Bidirectional; 
    // this.Configuration.SyncTables.Add(zyxySyncTable); 
     this.Synchronize(); 
    } 
} 

public class ZyxyServerSyncProvider : SqlSyncProvider 
{ 
    public ZyxyServerSyncProvider() 
    { 
     Utility util = new Utility(); 
     SqlConnection serverConn = new SqlConnection(util.ServerConnString); 
     this.Connection = serverConn; 
     this.ScopeName = "DISS_Sync_Scope"; 
     //Retrieve a new anchor value from the server. We use a timestamp value 
     //that is retrieved and stored in the client database. 
     //During each sync the new and last anchor values are used to determine the set of changes 
     SqlCommand selectNewAnchorCommand = new SqlCommand(); 
     string newAnchorVariable = "@" + SyncSession.SyncNewReceivedAnchor; 
     selectNewAnchorCommand.CommandText = 
      "SELECT " + newAnchorVariable + " = change_tracking_current_version()"; 
     selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.BigInt); 
     selectNewAnchorCommand.Parameters[newAnchorVariable].Direction = ParameterDirection.Output; 
     selectNewAnchorCommand.Connection = serverConn; 
     // this.SelectNewAnchorCommand = selectNewAnchorCommand; // SF 2.1 commented out because SelectNewAnchorCommand isn't there. 



     SqlSyncAdapterBuilder zyxyBuilder = new SqlSyncAdapterBuilder(serverConn); 

     zyxyBuilder.TableName = "dbo.ZyxySync"; 
     zyxyBuilder.ChangeTrackingType = ChangeTrackingType.SqlServerChangeTracking; 

     SyncAdapter zyxySyncAdapter = zyxyBuilder.ToSyncAdapter(); 
     zyxySyncAdapter.TableName = "ZyxySync"; 
     // this.SyncAdapters.Add(zyxySyncAdapter); // SF 2.1 commented out because SelectNewAnchorCommand isn't there. 

    } 
} 

public class ZyxyClientSyncProvider : SqlSyncProvider 

{ 

    public ZyxyClientSyncProvider() 
    { 
     Utility util = new Utility(); 
     SqlConnection clientConn = new SqlConnection(util.ClientConnString); 
     this.Connection = clientConn; 
     this.ScopeName = "DISS_Sync_Scope"; 
    } 
} 

public class Utility 
{ 
    public string ClientConnString 
    { 
     get { return @"Some connection string such as in the above code sample"; } 
    } 

    public string ServerConnString 
    { 
     get { return @"Some serverconnection string such as in the above code sample";  } 
    } 
} 
} 

4) 위를 성공적으로 두 개의 연속적인 동기화 세션 (예 : 양 끝에서 같은 레코드가 업데이트 될 때)이 해결되어야 할 때 양쪽 끝에서 INSERT, UPDATE 및 DELETE가 동시에 발생했을 때 양방향으로 동기화됩니다. 해결해야 할 충돌이있는 경우 추가 테스트를 수행해야합니다. Sync Framework는 기본적으로 그러한 충돌을 어떻게 해결합니까? 우리는이 설정을 조정하여 다음 중 하나를 기반으로 승자를 설정한다고 가정합니다. - 타임 스탬프 값 - 복제본 - 사용자 역할 - 거래 유형 -

어쨌든 저는 웹에서 알아 내기 힘든 시간을 보냈기 때문에 어쨌든 누군가를 돕기를 바랍니다. 행운을 빕니다!

Zyxy

내가 그렇게 할 것입니다 의심 LOL
+0

정확히 어떤 공급자로부터 상속받을 수 있는지 확실하지 않습니다 ... 어댑터 빌더 및 앵커 명령도 사용되지 않습니다. – JuneT

+0

@JuneT 위의 동기화는 테스트 테이블 일뿐입니다. 다음 목표는 모든 변경 추적 관련 메타 테이블과 해당 저장 프로 시저를 다른 스키마에 저장하여 현재 사용자 (기본) 테이블과 저장된 procs와 섞인 것처럼 시각적 오염을 일으키지 않도록하는 것입니다. 두 테이블은 양방향으로 동기화되지만 (이미 GUID를 사용함) 대부분의 테이블은 주 서버에서 클라이언트 복제본으로 단방향으로 동기화됩니다. 모든 코드 제안을 부탁드립니다. 위에서 한 것처럼, 내가 작동하도록 만들면 모든 사람들의 이익을 위해 코드를 게시 할 것입니다. 감사! – Zyxy

+0

@Zyxy, 당신은 최신의 .net 4.5 프레임 워크에서 동기화 프레임 워크에 대한 업데이트가 있는지를 알려줄 수 있습니까? 더 좋은 해결책이 없습니다 .2 개의 SQL 익스프레스 dbs를 동기화해야하므로 복제를 사용할 수 없습니다. – Dragon