C# Synchronizacja bazy lokalnej i online

1

Cześć wszystkim - mam problem,

piszę program, który będzie posiadał w sobie wbudowaną bazę danych (lokalną - offline) dla pracowników danej firmy.
W momencie gdy taki pracownik kliknie przycisk "aktualizuj" to baza danych offline ma się zsynchronizować z tą bazą danych na serwerze tzn. wysłać dane które zostały zmienione, dodane w bazie lokalnej i pobrać te, które ktoś zmienił w bazie online.

Chodzi o to abym w bazach lokalnych miał to samo co w bazie online - po kliknięciu przycisku aktualizuj.
Zastanawiam się zatem, jak zrobić pobieranie do bazy lokalnej rekordów nowo utworzonych, zmodyfikowanych oraz w jaki sposób usuwać rekordy.
Baza danych online to MySQL, natomiast baza lokalna to Access ... - ale problem rozwiążę chyba wprowadzając dodatkową kolumnę w każdej tabeli informującej o ostatniej modyfikacji.

Chcę to zrobić w możliwie łatwy sposób, ale tak aby baza danych się nie zapychała.... - tzn. rozumiem, że najszybciej byłoby aby w momencie gdy ktoś kliknie "aktualizuj" cała baza danych online była pobierana do online - ale w przypadku dużej liczby rekordów będzie to niepotrzebny balast.
Myślę, że można to zrobić wprowadzając do tabel w bazie danych dodatkowe kolumny informujące o tym, czy jakiś rekord był modyfikowany - a jeżeli był to kiedy (na tej podstawie baza online ściągnie, albo nie dany rekord) ....

[b]No dobrze, pokażę na przykładzie o co mi chodzi :[/b]
Załóżmy, że mamy dwóch pracowników (ich liczba może być większa) - każdy pracownik i baza online ma taką samą strukturę (chyba, że coś zmienić co mi pomoże np. dodać nową kolumnę to piszcie...).
Baza danych poniżej - jest aktualna, tzn te same dane znajdują się w każdej bazie lokalnej i bazie online :

[url=http://www.fotoszok.pl/show.p[...]64_baza-danych.jpg[/img][/url]

[b]-> Dodawanie nowego rekordu :[/b]

Załóżmy, że pracownik 2 będzie chciał utworzyć nowy rekord, jak pobrać tylko ten nowo utworzony rekord przez pracownika 1 ? Co w momencie gdy pracownik 1 także będzie chciał utworzyć nowy rekord - zakładam, że wszystkie operacje są wykonywane na bazie offline - dopiero w momencie aktualizacji pracownik przesyła dane do bazy online.

[url=http://www.fotoszok.pl/show.p[...]70_baza-danych.jpg[/img][/url]

Zakładając, że pole ID będzie to klucz główny - nowe rekordy mogę rozpoznawać w ten sposób, że zrobię zapytanie SELECT do bazy online o wszystkie rekordy których ID jest większe niż największe w bazie offline.
Tzn. -> Select * from pracownicy where id > 3
W tym przypadku jeżeli baza danych mi coś zwróci - oznacza to, że ktoś dodał nowe rekordy.

No dobrze, ale co w przypadku gdy pracownik 1 będzie chciał także utworzyć nowy rekord przed aktualizacją bazy danych tzn.

[url=http://www.fotoszok.pl/show.p[...]71_baza-danych.jpg[/img][/url]

Numer ID nowego rekordu będzie taki sam w bazie offline pracownika 1 i pracownika 2.
Co w tej sytuacji zrobić - jak pogodzić tworzenie nowych rekordów offline - kto pierwszy doda rekord ten lepszy ...?
I w momencie gdy przy dodawaniu rekordu przez pracownika1 wyskoczy błąd (Id istnieje), to zmienić id na największy możliwy (musiałbym to zrobić także ze wszystkimi powiązaniami w bazie offline, które dotyczyły tego rekordu)....

[b]-> modyfikacja [/b]

Problem dodawania nowych rekordów, nie jest taki ciężki - cięższe wydaje mi się sprawdzanie czy coś zostało modyfikowane.
[url=http://www.fotoszok.pl/show.p[...]99_baza-danych.jpg[/img][/url]

Załóżmy, że pracownik 2 będzie chciał zmienić rekord 2 i zaktualizuje go w bazie danych online -> zmienione pole to nazwisko - przy czym, gdzie rekord jest modyfikowany to zmieniam także pole data M (data modyfikacji)....

I teraz w jaki sposób ma to odczytać pracownik1, że coś w bazie online różni się od tego co on posiada ?
Przecież nie będę robił zapytania w postaci czy data modyfikacji 1 rekordu offline == data modyfikacji 1 rekordu online, czy data modyfikacji 2 rekordu offline == data modyfikacji 2 rekordu online ....
W ten sposób do bazy danych musiałbym wysłać tyle zapytań ile mam rekordów - a to wydaje mi się ( nie jestem pewien) może zapchać bazę danych...

Może zapytanie skonstruować w ten sposób, że z bazy offline wybiorę ostatnią datę modyfikacji i sprawdzę czy jest jakaś data w bazie online "później" od tej daty tzn.
zapiszę sobie najnowszą datę modyfikacji bazy offline pracownika 1 (w tym przypadku) 15-stego

Select * from pracownicy where data_M > 15

W wyniku powinienem dostać rekordy, których nie mam zaktualizowanych w bazie danych tzn. utworzone po 15 i zmodyfikowane ... czyli nie musiałbym w tym przypadku szukać rekordów nowych - czy dobrze myślę ?

Właśnie to przemyślałem i chyba nie ma tak prosto - bo jak wcześniej pisałem, programy pracują na bazie offline i w momencie kliknięcia aktualizuj łącza się online - więc pracownik1 pracując offline może też w międzyczasie (przed aktualizacją bazy) dokonać jakiejś modyfikacji w dniu późniejszym np.:

[url=http://www.fotoszok.pl/show.p[...]23_baza-danych.jpg[/img][/url]

I teraz w momencie, gdyby pracownik1 chciał zaktualizować bazę w w/w sposób dokonałby tego dla
Select * from pracownicy where data_M > 25 - czyli nie zobaczyłby zmodyfikowanego rekordu z dnia 19 !!!
Jak sobie z tym poradzić ...?
W jaki sposób skonstruować zapytanie - może dodać jakieś pole do tabeli, które będzie pamiętało coś innego....?

Pozostaje jeszcze kwestia usuwania - jak to zrobić, jeżeli np. pracownik2 usunie rekord1 - nie może go raczej usunąć z bazy online, gdyż w ten sposób pracownik 1 nie dostanie informacji o tym że taki rekord ma być usunięty...

Myślę, że wiecie już o co chodzi - chce za pomocą dodatkowych kolumn w tabeli skonstruować synchronizację baz danych - tak aby były przechowywane informacje o tym czy coś zostało zmodyfikowane itp...
Prosiłbym o pomoc

Może byłby ktoś w stanie mi to rozrysować, albo opisać tak abym zrozumiał.
Dziękuję za pomoc ;)

1

każda tabela, która ma być synchronizowana musi mieć dodatkowe pole typu timestamp. Dodatkowo trigger na insert i update aktualizujący automatycznie tą kolumnę. Odnośnie delete są trzy drogi - albo nie usuwać fizycznie rekordów tylko zaznaczać je jako usunięte albo za każdym razem wysyłać listę wszystkich ID w danej tabeli i usuwać te, których nie ma albo dodatkowa tabela, gdzie będzie id usuniętych i timestamp kiedy były usuwane.
Tabele w bazie podrzędnej muszą mieć dwa ID - lokalne i globalne. Lokalne nadawane automatycznie natomiast globalne takie samo jak w bazie głównej.

Teraz tak jeśli wysyłasz cokolwiek z bazy lokalnej do głównej to MUSISZ wysyłać ZAWSZE globalne ID. Jeśli go nie ma (bo np. dodałeś nowy towar lokalnie i nie ma go jeszcze w bazie głównej) to musisz najpierw dodać towar do bazy głównej, pobrać jego id z bazie głównej i zapisać w bazie lokalnej i dopiero teraz możesz wysyłać np. zamówienia z tym towarem.

Za każdym razem musisz gdzieś zapamiętać timestamp ostatniej aktualizacji po to aby niepotrzebnie nie pobierać danych, które się nie zmieniły.

Działa już dłuższy czas z kilkoma bazami lokalnymi (tu akurat mssql compact) i nie było większych problemów.

Jedyny problem może być wtedy jeśli ktoś przestawi na urządzeniu datę do przodu, zrobi aktualizację, przestawi datę do tyłu i coś zmieni - wtedy rekordy, które były zmienione między aktualizacją a datą, która była wtedy ustawiona są w tzw czarnej dupie - bez ręcznego grzebania się nie zaktualizują.

1

Replikacja transakacyjna. Poczytaj.

2

czaisz koleś, że to wątek sprzed ponad TRZECH LAT!

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0