Синхронизация данных со столбцами идентификаторов между серверами SQL Express с использованием Entity Framework - PullRequest
2 голосов
/ 10 января 2012

Я спроектировал базу данных, чей файл MDF будет скопирован в удаленные офисы, поэтому в основном у меня будут разные базы данных с одинаковой схемой.Однако некоторые таблицы из этих баз данных должны будут содержать те же данные.Сначала я был счастлив, потому что знал, что их было легко синхронизировать, используя столбцы RowVersion в каждой таблице, но потом я вспомнил, что столбцы первичного ключа в этих таблицах (столбцы с именем «ID») также являются столбцами идентификаторов.Поэтому я понятия не имею, как синхронизировать их так, чтобы они были идентичными.С такими же идентификаторами и все.Также я делаю это через Entity Framework, который находится между SQL Server 2008 R2 Express и .NET Framework 4 WCF Service.Есть какие-нибудь подсказки?Обратите внимание, что это односторонняя синхронизация, удаленные офисы должны реплицировать эти таблицы из основной базы данных, но они не могут их изменять и записывать изменения обратно.

Исходный поток был запущен здесь: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/e5f89bac-959c-490a-befc-a80d5aa9a9a5/ но я еще не пришел к решению.Если вы посмотрите на поток, на который я ссылался, то увидите, что предлагаемое решение заключалось в том, чтобы прикрепить записи из основного контекста БД к контексту клиентской БД и вызвать метод ApplyCurrentValues ​​для обновления клиентской БД.Однако я пришел к выводу, что он не будет работать вообще по следующим причинам:

  1. Различные значения EntityKey между данными из двух контекстов.Вы не можете прикрепить запись к контексту, если EntityKey этой записи не соответствует контексту.Чтобы обойти эту проблему, мне пришлось преобразовать объект из mainDB в объект из clientDB с помощью AutoMapper и вручную установить EntityKey перед присоединением записи к контексту clientDB.
  2. Если вы хотите добавить новую запись (еслиодин существует в mainDB, но не в clientDB) вы не можете использовать Attach.Если запись, которую вы пытаетесь прикрепить, не существует в хранилище, EF выдаст вам исключение.
  3. Если вы хотите добавить новую запись, вы должны использовать AddObject, но это подразумевает EntityKeyгенерируется автоматически, и вы не сможете контролировать столбец идентификаторов.Если вы попытаетесь установить EntityKey вручную перед добавлением новой записи, EF выдаст вам исключение.

Итак, вопрос в том, как я могу реплицировать данные из основной БД в клиентскую БДиспользуя EntityFramework?

1 Ответ

1 голос
/ 23 марта 2012

Недавно мы внедрили это решение, однако наша база данных была достаточно простой, и у нас был один метасервер (мы называем его мета-сервером, так как это наш сервер, который содержит только идентификаторы), и у нас есть серверы данных. У нас есть три сервера данных, которые выполняют трехстороннюю синхронизацию. Первоначально у нас было только три сервера, но вставка новых идентификаторов была проблемой, и мы не хотели использовать GUID, потому что он не читается человеком.

Итак, мы ввели концепцию IdentityServer (мы назвали его MetaServer), в которой размещается простая веб-служба и простая база данных, база данных состоит из таблиц, в которых используются только Identities, для проверки синхронизации используются Hash и LastUpdate, Hash и LastUpdate.

Например, на Meta Server есть следующие две таблицы:

Tickets
   TicketID (Primary Key,Identity)
   LastUpdate (DateTime)
   Hash (Hash of Ticket)

Tasks
   TaskID (Primary Key, Identity)
   LastUpdate (DateTime)
   Hash (Hash of Task)

Теперь серверы данных будут содержать билеты следующим образом,

Tickets
   TicketID (Primary Key)
   Subject
   Message
   ... 
   ...
Tasks
   TaskID (Primary Key) 
   Subject
   Message
   ...
   ...

И наш метод Save в ObjectContext выглядит следующим образом:

Task task = new Task();
task.TaskID = MetaService.GetNewTaskID();


...
...
// following is save method, checking insert or update, as it is used in 
//synchronization, thats why i wrote it like this
void SaveTask(Task task){
   Task copy = ObjectContext.Tasks.FirstOrDefault(x=>x.TaskID==task.TaskID);
   if(copy==null){
      copy = new Task();
      ObjectContext.Tasks.AddObject(copy);
   }
   CloneData(task,copy);
   ObjectContext.SaveChanges();
}

Чтобы выполнить синхронизацию, я бы предложил добавить такую ​​таблицу, которая будет сохранять каждое изменение в метасервере (мастер-сервере)

Changes
  ChangeID
  ChangeType = Insert,Update,Delete
  ChangeTable
  ChangeKey
  ChangeTime

Который затем каждый сервер данных может читать с Meta Server и обновлять изменения ...

...