https://buraksenyurt.com/Burak Selim Şenyurt - Ado.Net Sync Services2020-12-27T13:16:22+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/Ado-Net-Senkronizasyon-Servisleri(Sync-Services-for-Ado-Net)-bsenyurt-com-danAdo.Net Senkronizasyon Servisleri(Sync Services for Ado.Net)2009-01-03T10:00:00+00:00bsenyurt<p><span style="font-size: small;"><span style="font-family: Verdana;">Değerli Okurlarım Merhabalar,</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Birbirleri ile sürekli bağlantı halinde <span style="text-decoration: underline;">olamayan</span> <strong>istemci/sunucu(Client/Server)</strong> mimarilerinde en büyük problemlerden biriside verilerin karşılıklı veya tek taraflı olaraktan senkronize edilmeleridir. Çoğu büyük çaplı saha uygulamasında, sunucu tarafındaki veri kaynaklarının istemcide kullanıldığı durumlar söz konusudur. Bu noktada istemcilerin sürekli bağlı kalamadıkları bir ortamın var olması olasıdır <strong>(Occasionally Connected Enivronments)</strong>. Nitekim istemci ve sunucu arasında kablosuz bağlantı olma ihtimali oldukça yüksektir. Nitekim günümüz teknolojileri düşünüldüğünde istemci uygulamaların bir çoğu mobil cihazlar ile, diz üstü bilgisayarlar üzerinde koşmaktadır. Bu tabiki daha çok saha elemanlarının işin içerisine girdiği senaryolardır.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Söz gelimi günlük ürün fiyatlandırmalarını kullanarak satış yapan personelin mobil cihazlara sahip olduğu bir durumda, istemcilerin sunucuya sürekli olarak bağlı kalmaları saha üzerinde son derece zor olabilir. <em>(Mobil cihazlar, modern cep telefonları ve PDA' ler olabileceği gibi dizüstü bilgisayarlarda olabilir.)</em> Buna rağmen istemcinin söz konusu veriyi kullanarak çalışabilmesi de istenebilir. Diğer taraftan istemcinin sunucuya bağlandığı hallerde ortak veri üzerindeki değişikliklerini göndermesi ve hatta var olan farklılıkları kendi sistemine çekmeside istenebilir. </span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu iki taraflı bir senkronizasyon anlamına gelmektedir ki, iki tarafında birbirleri üzerindeki verileri senkronize etmeleri sırasında pek çok güçlükle karşılaşılacaktır. Nitekim bu vakada eş zamanlı bağlı olan kullanıcıların ortak verilerde yapacağı değişikliklerin ele alınması gerekir ki bunlar çakışmalara<strong>(Conflicts)</strong> neden olmaktadır. Bazı durumlarda ise sadece sunucudaki farklılıkların istemciye aktarılması veya tam tersi söz konusudur. Bu durumlarda senkronizasyonu yönetmek nispeten biraz daha kolaydır. Ancak hangi vaka olursa olsun her iki uçta yer alan verinin kolay kodlanabilir, yönetilebilir bir biçimde senkronize edilmeleri istenir. En azından geliştiriciler için bu önemlidir.</span></span></p>
<blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Ado.Net senkronizasyon servisleri esas itibariyle Microsoft Sync Framework(MSF) altyapısının bir parçasıdır. MSF altyapısı içerisinde Sync Services for File Systems ve Sync Services for FeedSync isimli iki alt açılım daha vardır. Sync Services For Ado.Net özel olarak istemci ve sunucu arasındaki veri senkronizasyonun sağlanmasında Ado.Net' in üstüne gelmiş olan bir tamamlayıcı olarak düşünülebilir. (Microsoft Sync Framework için <a href="http://msdn.microsoft.com/en-us/sync/default.aspx">MSDN</a>' den detaylı bilgi alınabilir.)</span></span></p>
</blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Senkronizasyon işlemlerinde bilinen ve kullanılan farklı teknikler de söz konusudur. Örneğin <strong>Remote Data Access(RDA)</strong> veya <strong>Merge Replication</strong>. <strong>RDA</strong>, <strong>SQL Server Compact 3.5</strong> ile diğer bir <strong>SQL</strong> veritabanı arasındaki senkronizasyon işlemlerinde ele alınır. <strong>Merge</strong> <strong>Replication</strong> ise <strong>SQL</strong> veritabanlarının herhangi versiyonları arasındaki senkronizasyon süreçlerinde kullanılır. Özellikle <strong>Merge Replication </strong>veritabanı yöneticilerine hitap eder ve <strong>SQL</strong> kaynaklarını hedefler. </span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Ancak <strong>ADO.Net Senkronizasyon Servisleri </strong>ile <strong>WCF(Windows Communication Foundation)</strong> hizmetlerini kullanarak, sunucu tarafında farklı veri kaynaklarına erişebilmek mümkündür. Diğer taraftan <strong>Ado.Net Senkronizasyon Servisleri</strong> daha çok uygulama geliştiricileri hedef alır. Eğer istemci tarafının senkronize edeceği veri kümesi <strong>SQL</strong> dışında bir kaynak ise mutlaka <strong>Ado.Net Senkronizasyon Servisi</strong> göz önüne alınmalıdır. <strong>RDA</strong>, <strong>Merge</strong> <strong>Replication</strong> ve <strong>Ado.Net Senkronizasypn Servisleri</strong> arasındaki karşılaştırmaları aşağıdaki tablodan da inceleyebilirsiniz. Özellikle karar verme aşamasında bu tablodaki bilgilerden de yararlanılabilir.</span></span></p>
<table style="border-collapse: collapse; background- width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<th rowspan="2"><span style="font-size: small;"><span style="font-family: Verdana;">Anahtar Özellik</span></span></th>
<th colspan="3"><span style="font-size: small;"><span style="font-family: Verdana;">Kullanılabilen Teknikler</span></span></th>
</tr>
<tr>
<th><span style="font-size: small;"><span style="font-family: Verdana;">RDA<br /> (Remote Data Access)</span></span></th>
<th><span style="font-size: small;"><span style="font-family: Verdana;">Merge Replication </span></span></th>
<th><span style="font-size: small;"><span style="font-family: Verdana;">Ado.Net Sync Services </span></span></th>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Servisler üzerinden senkronizasyon sağlanması</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Farklı veri kaynakları için destek</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;"> Değişimsel(Incremental) farklılıkların takibi</span></span></td>
<td align="center"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> <span style="color: #ff0000;">Yok</span>*</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Çakışma(Conflict) kontrolü ve çözümleri</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">İstemci tarafında View' ların kolayca oluşturulması<em>(Görsel derslerde ele alınacaktır)</em></span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Otomaik şema(Schema) ve veri oluşturma</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Büyük boyutlu DataSet desteği</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Otomaik olarak şema değişikliklerini üretmek</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
</tr>
<tr>
<td><span style="font-size: small;"><span style="font-family: Verdana;">Veriyi tekradan birleştirmek(Repartition)</span></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #008000;"> Var</span></strong></span></td>
<td align="center"><span style="font-size: small;"><strong> <span style="font-family: Verdana; color: #ff0000;"> Yok</span></strong></span></td>
</tr>
<tr>
<td colspan="4"><span style="font-size: small;"><span style="font-family: Verdana;"><strong>*</strong><em> RDA değişimsel upload' ları destekler. Verinin istemci tarafına alınmasında Snapshot modelini kullanılır. Yani istemci tarafına tüm veriyi indirir.</em></span></span></td>
</tr>
</tbody>
</table>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Teknik açıdan bakldığında <strong>Ado.Net Senkronizasyon Servisleri</strong> temel olarak aşağıdaki 3 assembly' dan oluşmaktadır.<strong> Ado.Net Senkronizasyon Servisleri</strong> tarafların sahip olduğu veri sağlayıcılarına göre <strong>2 katlı(Two Tier), N-katlı(N-Tier) </strong>ve <strong>Servis Bazlı Mimariye(Service Oriented Architecture)</strong> uygun olacak şekilde kullanılabilmektedir. Eğer istemci ve sunucu <strong>Ado.Net </strong> veri sağlayıcıları üzerinden konuşuyorlarsa iki katlı veya n katlı modeller tercih edilebilir. Ancak sunucu tarafından <strong>SQL</strong> dışı bir veri kaynağı var ise<em>(Söz gelimi bir XML deposu, Active Directory vb...)</em> bu durumda servis yönemlimli olacak şekilde bir geliştirme yapılmalıdır. Senkronizasyon her zaman için istemci tarafında başlatılan bir olaydır ve temel olarak 4 farklı tipte senkronizasyon tekniği kullanılmaktadır.</span></span></p>
<table style="border-collapse: collapse; background- width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 121px; background-color: #ffccaa;" bgcolor="#336699" width="121"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Kullanılan Teknik</span></strong></span></td>
<td style="width: 121px; background-color: #ffccaa;" align="left" bgcolor="#336699"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Açıklama</span></strong></span></td>
</tr>
<tr>
<td valign="top" width="121"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Snapshot</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;">Bu teknikte senkronizasyon işlemi başlatıldığında sunucu tarafındaki verinin tamamı istemci tarafına indirilir. Bir başka deyişle <strong>değişimsel(incremental)</strong> farklılıklar göz önüne alınmaz, sürekli olarak son hal indirilir.</span></span></td>
</tr>
<tr>
<td valign="top" width="121"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Download-Only</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;">Bir önceki senkronizasyona göre farklı olan verilerin download edilmesi söz konusudur. Bir başka deyişle sadece değişimsel verilerin indirilmesi söz konusudur.</span></span></td>
</tr>
<tr>
<td valign="top" width="121"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Upload-Only</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;"> Senkronizasyon işleminde istemci tarafındaki veriler üzerinde yapılan değişiklikler ve yeni eklemelerin sunucu tarafına taşınması söz konusudur. Söz gelimi satış ekibinin herhangibir ürün satışı için yaptığı girişler veya güncellemeler buna örnek bir vaka olarak düşünülebilir.</span></span></td>
</tr>
<tr>
<td valign="top" width="121"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Bidirectional</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;">Çift yönlü senkronizasyon söz konusudur. Söz gelimi bir kargo dağıtım firmasının saha elemanlarının dağıtılacak kargo bilgilerini alması ve dağıtıma ait bilgileri sunucu üzerine güncellemesi gibi bir vaka örnek olarak düşünülebilir. Bu noktada özellikle senkronizasyon işlemleri sırasında oluşabilecek eş zamanlı veri <strong>çakışmalarının(Conflicts)</strong> kontrol altına alınması gerekir.</span></span></td>
</tr>
</tbody>
</table>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu noktada belkide senkronizasyon servislerinin katlı mimarideki konumlarını ele almak yararlı olabilir. Bu amaçla aşağıdaki çizelgelerden yararlanabiliriz.</span></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">2 Katlı Mimari;</span></strong></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_1.gif" alt="" width="537" height="349" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">İki katlı modelde sunucu ve istemci tarafında senkronizasyon işlemine tabi olan nesneler bazen aynı uygulama üzerinde bulunmaktadır. Her ne kadar çok fazla tavsiye etmesemde iki katlı modelin uygulanması özellikle <strong>Visual Studio 2008</strong> ortamında son derece kolaydır. Ancak gerçek hayat uygulamalarında çoğunlukla sunucu senkronizasyonunu bir servis veya başka bir uygulama tek başına üstlenir.</span></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">N-Katlı Mimari;</span></strong></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_2.gif" alt="" width="601" height="349" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">N-katlı modelde istemci ve sunucu üzerindeki veritabanları arasındaki iletişim sırasında devreye giren ve ayrı bir katta duran <strong>Servis-Proxy</strong> tipleri mevcuttur. Genellikle istemci ve sunucu veribanları arasında doğrudan bağlantıyı gerektirmediği için 2 katlı mimariye göre daha fazla tercih edilmektedir.</span></span></p>
<p><span style="font-size: small;"><strong><span style="font-family: Verdana;">Servis Bazlı Mimari;</span></strong></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_3.gif" alt="" width="600" height="348" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>SOA</strong> modeli sunucu tarafındaki veri kaynağının <strong>SQL</strong> olmadığı durumlarda ele alınabilir. Bu sebepten dolayı sunucu tarafında sunucu senkronizasyon sağlayıcısı veya senkronizasyon adaptörleri bulunmamaktadır. Bu mimaride istemcinin sunucu tarafı ile mutlak suretle bir servis üzerinden konuşuyor olması gerekmektedir. Bir başka deyişle sunucu senkronizasyon sağlayıcısı ile senkronizasyon adaptörlerinin görevini servis tarafı üstlenmektedir. Bu noktada servis tarafında <strong> WCF</strong> gibi gelişmiş modellerin kullanılmasıda mümkündür.<em>(İlerleyen görsel derslerimizde bu konuyuda incelemeye çalışıyor olacağız.)</em></span></span></p>
<blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;">.Net Framework tarafından bakıldığında Ado.Net Sync Service' ler aşağıdaki 3 temel assembly ve tiplerinden yaralanmaktadır.</span></span></p>
<ul>
<li><span style="font-size: small;"><span style="font-family: Verdana;">Microsoft.Synchronization.Data.dll assembly (Synchronization Agent, Synchronization Tables ve Synchronization Groups)</span></span></li>
<li><span style="font-size: small;"><span style="font-family: Verdana;">Microsoft. Synchronization.Data.SqlServerCe.dll (Client Synchronization Provider)</span></span></li>
<li><span style="font-size: small;"><span style="font-family: Verdana;">Microsoft. Synchronization.Data.Server.dll (Server Synchronization Provider ve Synchronization Adapters)</span></span></li>
</ul>
<p><span style="font-size: small;"><img src="/makale/images/mk265_4.gif" alt="" width="281" height="117" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">(Tabi Sync Service For Ado.Net' i kullanabilmek için ilgili <a href="http://www.microsoft.com/downloads/details.aspx?familyid=75FEF59F-1B5E-49BC-A21A-9EF4F34DE6FC&displaylang=en">sürümünü</a> indirip kurmanız gerekmektedir. Makalenin yazıldığı tarihten sonra farklı versiyonların çıkması ve muhtemel değişimlerin olmasınında söz konusu olduğunu belirtmek isterim. Makalemizde Microsoft Sync Framework 2.0 CTP sürümü içerisindeki Sync Services For Ado.Net alt yapısı kullanılmaktadır.)</span></span></p>
</blockquote>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Makalemizin bundan sonraki bölümünde teknik detayları bir kenara bırakıp çok basit bir örnek üzerinden konuyu daha net bir şekilde kavramaya çalışacağız. Örnekte kullanılmakta olan <strong>Windows</strong> uygulaması üzerinde, <strong>Azon</strong> isimli örnek veritabanında yer alan <strong>Kitap</strong> isimli tablo için <strong>çift yönlü(Bidirectional)</strong> senkronizasyon işlemleri yapılmaktadır. Ancak elbette istediğiniz tipte bir veritabanı ve tablolarını kullanabilirsiniz. Tablomuzun ilk hali aşağıdaki şekilde görüldüğü gibidir ve bu noktadaki hali oldukça önemlidir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_5.gif" alt="" width="573" height="222" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Biraz sonra tablonun şu anki alan yapısının senkronizasyon desteği için değiştiğini göreceğiz :) Şimdi örnek Windows uygulamamıza <strong>Local Database Cache</strong> isimli yeni bir <strong>şabloun öğe(Template Item)</strong> ekliyoruz.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_6.gif" alt="" width="570" height="365" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><strong>Sync</strong> uzantılı <strong>LocalAzon</strong> isimli öğe temel olarak senkronizasyon işlemleri ile ilişkili ayarları tutacaktır. Örneğin senkronizasyon tablolarına ait <strong>şema(Schema)</strong> bilgileri, <strong>bağlantı(Connection)</strong> ayarları, kodlama kısımları vb... Bu nedenle ilk olarak karşımıza aşağıdaki pencere çıkacaktır.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_7.gif" alt="" width="640" height="491" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Burada ilk etapta sunucu veri kaynağı ve istemci veri kaynağına ait bağlantılar belirtilir. Dikkat edileceği üzere sunucu bağlantısı <strong>Sql</strong> <strong>Server</strong><em>(ki örnekte SQL Server 2008 üzerinde durmaktadır)</em> üzerindeki veritabanını işaret etmektedir. İstemci bağlantısında ise <strong>sdf</strong> uzantısı ile dikkat çeken ve biraz sonra oluşturulacak olan <strong>Sql Server Compact 3.5</strong> sürümünde bir veritabanı dosyası adı bulunmaktadır. <strong>Advanced</strong> kısmına baktığımızda ise senkronizasyon için <strong>transaction</strong> tanımlaması yapılabildiği de dikkati çekmektedir. Yani tüm tabloların senkronizasyon işlemlerinin ortak bir transaction içerisinde gerçekleştirilmesi isteği belirtilebilmektedir. Diğer taraftan önemli noktalardan biriside sunucu ve istemci proje lokasyonlarıdır. </span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Şu an itibariyle her iki değerde geliştirmekte olduğumuz projeyi işaret etmektedir. Elbetteki gerçek hayat vakalarında özellikle sunucu proje lokasyonu başka bir uygulamayı işaret etmektedir.<em>(N-Tier veya SOA uyarlaması)</em>. Bu adımı tamamlamadan önce sol taraftaki <strong>Application</strong> kısmına yeni bir <strong>offline</strong> <strong>table</strong> eklenmesi gerekmektedir. Bu amaçla, <strong>Add</strong> düğmesine basıldıktan sonra aşağıdaki ekran görüntüsü ile karşılaşılacaktır.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_8.gif" alt="" width="600" height="400" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu kısımda senkronizasyon sürecine dahil olacak tablo(tablolar) veya veritabanı nesneleri seçilir. Dikkat edileceği üzere verinin istemci tarafına indirilme şekli belirlenebilmektedir. Şu andaki seçime göre ilk senkronizasyon işleminden sonra <strong>değişimsel(Incremental)</strong> ve yeni eklemelerin indirilmesi seçeneği etkindir. </span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Senkronizasyon işlemleri sırasındaki önemli noktalardan biriside, istemci ve sunucu arasındaki bağlantının tekrardan sağlanması sonrasında karşılıklı olarak verilerde yapılan işlemlerin nasıl ayırt edilebileceğidir. Söz gelimi yeni güncelleştirmeler, silmeler veya eklemeler nasıl ayırt edilebililr. Bu sebepten <strong>update</strong> işlemleri için varsayılan olarak <strong>LastEditDate</strong>, <strong>insert</strong> işlemleri için <strong>CreationDate</strong> isimli iki yeni alanın <strong>Kitap</strong> isimli tabloya eklenmesi söz konusudur. Diğer taraftan silinen satırlar <strong>_Tombstone</strong> uzantılı bir tabloda saklanacaktır ve bu şekilde takip edilebilecektir. <strong>New</strong> veya <strong>Edit</strong> düğmelerinden yararlanarak söz konusu parametrelerin farklı isimlerde oluşturulmalarıda sağlanabilir. Burada geliştiricilerin hayatını kolaylaştıran bir linkte bulunmaktadır. Tablo eklenmesi tamamlandıktan sonra <strong>Configure</strong> <strong>Data</strong> <strong>Synchronization</strong> penceresinde yer alan <strong>Show</strong> <strong>Code</strong> <strong>Example</strong> linkine tıklandığında örnek bir kod parçası görülür.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_9.gif" alt="" width="633" height="238" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu kod parçası senkronize işleminin istemci tarafında başlatılacağı yerde kolayca kullanılabilmektedir ki biz de öyle yapıyor olacağız :) <strong>Configure Data Synchronization</strong> pencersinden çıkılırken istenirse senkronizasyon işlemleri için kullanılacak <strong>SQL</strong> <strong>Script</strong>' lerinin istemci uygulamaya eklenmesi sağlanabilir. Bunun için aşağıdaki penceredeki seçenekleri varsayılan halleri ile bırakmak yeterli olacaktır.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_10.gif" alt="" width="399" height="234" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Artık istemci tarafı için gerekli olan <strong>türlendirilmiş(Typed) DataSet</strong>, <strong>DataTable</strong> ve <strong>DataAdapter</strong> üretimleri yapılacaktır. Bunun için var olan Kitap tablosunun seçilmesi yeterlidir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_11.gif" alt="" width="575" height="451" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Senkronizasyon kodlarını eklemeden önce, istemci uygulamada ve sunucu veritabanında olan düzenleme ve ilaveleri analiz etmeye başlayabiliriz. İlk dikkat çekici nokta sunucu üzerindeki Azon veritabanında olan ilavelerdir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_12.gif" alt="" width="621" height="376" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Görüldüğü üzere güncelleme ve ekleme işlemlerinin takibi için Kitap tablosuna <strong>LastEditDate</strong> ve <strong>CreationDate</strong> isimli <strong>datetime</strong> tipinden iki alan eklenmiştir. Silinen satırların bilgisi için <strong>Kitap_Tombstone</strong> isimli bir tablo oluşturulmuştur. Bu tablo <strong>KitapId</strong> ve <strong>DeletionDate</strong> isimli alanları içermektedir. Böylece hangi satırın ne zaman silindiği bilgisi tutulabilmektedir. Diğer taraftan <strong>Insert</strong>, <strong>Update</strong> ve <strong>Delete</strong> işlemlerinden sonra devreye giren t<strong>etikleyicilerinde(triggers)</strong> eklendiği görülebilir. Triggerların içerikleri ve ne iş yaptıkları kısaca aşağıdaki tabloda açıklanmaktadır.</span></span></p>
<table style="border-collapse: collapse; background- width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="background-color: #ffccaa;" bgcolor="#336699"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Trigger</span></strong></span></td>
<td style="background-color: #ffccaa;" align="left" bgcolor="#336699" width="377"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Query</span></strong></span></td>
<td style="background-color: #ffccaa;" align="left" bgcolor="#336699" width="206"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Görevi</span></strong></span></td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Kitap_DeletionTrigger</span></strong></span></td>
<td align="left" width="377"><span style="font-size: small;"><span style="font-family: Verdana;">ALTER TRIGGER [dbo].[Kitap_DeletionTrigger] <br /> ON [dbo].[Kitap] <br /> AFTER DELETE <br /> AS <br /> SET NOCOUNT ON <br /> UPDATE [dbo].[Kitap_Tombstone] <br /> SET [DeletionDate] = GETUTCDATE() <br /> FROM deleted <br /> WHERE <br /> deleted.[KitapId] = [dbo].[Kitap_Tombstone].[KitapId] <br /> IF @@ROWCOUNT = 0 <br /> BEGIN <br /> INSERT INTO [dbo].[Kitap_Tombstone] <br /> ([KitapId], DeletionDate)<br /> SELECT [KitapId], GETUTCDATE() FROM deleted <br /> END </span></span></td>
<td align="left" valign="top" width="206"><span style="font-size: small;"><span style="font-family: Verdana;">Kitap tablosunda bir satır silindiğinde <strong>Kitap_Tombstone</strong> tablosunda silinen kayıdın var olup olmaması durumuna göre(<strong>@@ROWCOUNT</strong> değeri) ya <strong>DeletionDate</strong> alanın güncellemesi yapılır yada <strong>Kitap_Tombstone</strong> tablosuna silinen kayıt eklenir.</span></span></td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Kitap_UpdateTrigger</span></strong></span></td>
<td align="left" width="377"><span style="font-size: small;"><span style="font-family: Verdana;">ALTER TRIGGER [dbo].[Kitap_UpdateTrigger] <br /> ON [dbo].[Kitap] <br /> AFTER UPDATE <br /> AS <br /> BEGIN <br /> SET NOCOUNT ON <br /> UPDATE [dbo].[Kitap] <br /> SET [LastEditDate] = GETUTCDATE() FROM inserted <br /> WHERE inserted.[KitapId] = [dbo].[Kitap].[KitapId] <br /> END;</span></span></td>
<td align="left" valign="top" width="206"><span style="font-size: small;"><span style="font-family: Verdana;">Kitap tablosundan bir satır güncellendiğinde, o satırın <strong>LastEditDate</strong> alanına anlık zaman değeri atanır.</span></span></td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> Kitap_InsertTrigger</span></strong></span></td>
<td align="left" width="377"><span style="font-size: small;"><span style="font-family: Verdana;">ALTER TRIGGER [dbo].[Kitap_InsertTrigger] <br /> ON [dbo].[Kitap] <br /> AFTER INSERT <br /> AS <br /> BEGIN <br /> SET NOCOUNT ON <br /> UPDATE [dbo].[Kitap] <br /> SET [CreationDate] = GETUTCDATE() FROM inserted <br /> WHERE inserted.[KitapId] = [dbo].[Kitap].[KitapId] <br /> END;</span></span></td>
<td align="left" valign="top" width="206"><span style="font-size: small;"><span style="font-family: Verdana;">Kitap tablosuna yeni bir satır eklendikten sonra bu satırının <strong>CreationDate</strong> alanına o anki zaman değeri atanır.</span></span></td>
</tr>
</tbody>
</table>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Peki ya uygulama tarafındaki değişiklikler nelerdir?</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_13.gif" alt="" width="481" height="552" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Görüldüğü üzere <strong>Sync Services for Ado.Net</strong> için gerekli olan <strong>Microsoft.Synchronization.Data, Microsoft.Synchronization.Data.Server</strong> ve <strong>Microsoft.Synchronization.Data.SqlServerCe</strong> <strong>assembly</strong>' ları projeye referans olarak gelmektedir. Tüm senkronizasyon alt yapısına ait tipler bu <strong>assembly</strong>' lar içerisinde gelmektedir. Diğer taraftan istemci uygulamada yerel bir <strong>sdf</strong> dosyasıda oluşturulmuştur. Bu dosya <strong>local</strong> olarak çalışabilen <strong>Sql</strong> <strong>Server</strong> <strong>Compact</strong> <strong>3.5</strong> versiyonunda bir veritabanıdır. İstemci uygulamadaki görsel veri bağlı bileşenler için türlendirilmiş <strong>DataSet</strong> içeriği <strong>AzonDataSet.xsd</strong> adıyla oluşturulmuştur. Senkronizasyon ayarlarını ve işlemlerini üstlenen tipleri <strong>LocalAzon.sync</strong> öğesi barındırmaktadır. Bunlara ek olarak istemci tarafı için üretilen tiplere baktığımızda aşağıdaki sınıf diagramında yer alan temel öğeler dikkat çekmektedir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_15.gif" alt="" width="615" height="566" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Buradaki tiplerin temel işlevleri aşağıdaki tabloda belirtilmektedir.</span></span></p>
<table style="border-collapse: collapse; background- width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="background-color: #ffccaa;" bgcolor="#336699"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Kullanılan Sınıf</span></strong></span></td>
<td style="background-color: #ffccaa;" align="left" bgcolor="#336699"><span style="font-size: small;"><strong> <span style="font-family: Verdana;">Açıklama</span></strong></span></td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> DbServerSyncProvider </span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;"><strong> Microsoft.Synchronization.Data.Server.dll</strong> assembly' ı içerisinde yer alan bu sınıf <strong>ServerSyncProvider</strong> tipinden türemektedir. </span></span>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Sunucu üzerindeki senkronizasyon tablolarının bilgilerinin tutulması, sunucu üzerindeki verilerde son senkronizasyondan sonra olan değişikliklerin elde edilmesi, sunucu veritabanına <strong>değişimsel(incremental)</strong> farklılıkların aktarılması, <strong>çakışmaların(Conflicts)</strong> kontrol edilmesi gibi işlemleri üstlenir.</span></span></p>
</td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;"> SqlCeSyncProvider</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;"> <strong>Microsoft.Synchronization.Data.SqlServerCe.dll </strong>assembly'ı içerisinde yer almaktadır.</span></span>
<p><span style="font-size: small;"><span style="font-family: Verdana;">İstemci tarafında senkronizasyona dahil edilmiş tabloların bilgilerinin saklanması, istemci veritabanındaki son senkronizasyondan sonra olan değişikliklerin elde edilmesi, istemci veritabanına değişimsel farklılıkların aktarılması, çakışmaların tespit edilmesi gibi kritik ve önemli işlemleri üstlenir.</span></span></p>
</td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;">SyncAdapter</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;"> <strong>Microsoft.Synchronization.Data.Server.dll</strong> assembly' ı içerisinde yer alan bu sınıf <strong>DbServerSyncProvider</strong> ile sunucu veritabanı arasında köprü vazifesi görmektedir.</span></span>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Senkronize işleminde ele alınan her tablo için bu tipten türeyen bir sınıf üretilir. Bu adaptör nesneleri, senkronizasyonun tipine göre gerekli olan <strong>DbCommand</strong> örneklerini bir başka deyişle <strong>SQL</strong> sorgularını içerir.</span></span></p>
</td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;">SyncAgent</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;"> <strong>Microsoft.Synchronization.Data.dll </strong>assembly'ı içerisinde yer almaktadır. Tüm senkronizasyon sürecinin orkestrasyonunu üstlenmektedir.</span></span></td>
</tr>
<tr>
<td valign="top"><span style="font-size: small;"><strong><span style="font-family: Verdana;">SyncTable</span></strong></span></td>
<td align="left"><span style="font-size: small;"><span style="font-family: Verdana;"> <strong>Microsoft.Synchronization.Data.dll</strong> assembly'ı içerisinde bulunmaktadır. </span></span>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Senkronizasyon işlemine tabi olan tüm tablolar için istemci tarafında birer adet oluşturulur. <strong>SyncAgent</strong> tipi içerisinde <strong>Nested Type(Dahili Tip)</strong> şeklinde oluşturulmaktadır. Senkronizasyona dahil olan istemci tablolarına ait ayarları taşımak gibi görevleri vardır.</span></span></p>
</td>
</tr>
<tr>
<td colspan="2" valign="top"><span style="font-size: small;"><em><span style="font-family: Verdana;"> Makalede geliştirdiğimiz örnekte sunucu tarafı senkronizasyon tiplerininde istemci uygulama üzerinde oluşması normaldir. Nitekim, <strong>Configura Data Synchronization</strong> kısmındaki <strong> Application</strong> ayarlarına bakıldığında istemci ve sunucu uygulamaların aynı olduğu görülmektedir. Ancak gerçek vakalarda sunucu veri kaynağı ile iletişimi sağlayan ayrık bir uygulamanın servis bazlı olması söz konusudur ki bu durumda <strong>N-Tier </strong>veya SOA mimarisine geçilmiş olmaktadır.</span></em></span></td>
</tr>
</tbody>
</table>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Testlere başlamadan önce istmeci uygulamanın tasarımını basit olarak aşağıdaki gibi değiştirelim.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_14.gif" alt="" width="613" height="439" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Burada <strong>GridView</strong> kontrolü otomatik olarak <strong>AzonDataSet</strong> içerisindeki <strong>Kitap</strong> tablosuna bağlıdır ve üzerinde bağlantısız olarak veri ekleme, çıkarma, güncelleştirme işlemleri yapılabilmektedir. Diğer taraftan <strong>Senkronize</strong> <strong>Et</strong> başlıklı düğmenin içeriği aşağıdaki gibidir.</span></span></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ClientApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void kitapBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.kitapBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.azonDataSet);
}
private void Form1_Load(object sender, EventArgs e)
{
this.kitapTableAdapter.Fill(this.azonDataSet.Kitap);
}
private void btnSenkronizeEt_Click(object sender, EventArgs e)
{
LocalAzonSyncAgent syncAgent = new LocalAzonSyncAgent();
Microsoft.Synchronization.Data.SyncStatistics syncStats = syncAgent.Synchronize();
Form1_Load(null, null);
}
}
}</pre>
<p>Tahmin ettiğiniz gibi biz sadece button içeriğini ekliyoruz. Burada ilk olarak bir <strong>Agent</strong> nesnesi örnekleniyor. Sonrasında ise <strong>Synchronize</strong> metodu ile senkronizasyon işlemi başlatılıyor. Bu işlemin sonuçlarını istersek üretilen <strong>SyncStatistics</strong> tipi üzerinden elde edebiliriz ki bunu loglama amacıyla kullanabiliriz. Yaptığımız bu değişiklikler sonrasında uygulamayı test ettiğimizde özellikle çift yönlü olarak bir senkronizasyon işlemi yapılamadığını göreceğiz. Bu sorunu çözmek için aşağıdaki kod parçasında da görüldüğü gibi <strong>LocalKitap.sync</strong> kod dosyasının içeriğini değiştirmemiz ve senkronizasyon tipini söz konusu <strong>Kitap</strong> tablosu için belirtmemiz gerekmektedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace ClientApp {
public partial class LocalAzonSyncAgent {
partial void OnInitialized(){
Kitap.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional;
}
}
}</pre>
<p>Artık Kitap tablosu için çift yönlü olaraktan senkronizasyon kontrolü yapılacaktır. Bir başka deyişle hem istemci hemde sunucu tarafındaki değişiklikler senkronizasyon işlemleri sonrasında karşı tarafa iletilecek ve verilerin eşlenmesi sağlanacaktır. Elbette birden fazla tablo kullanılması halinde bu tabloların her biri için ayrı ayrı senkronizasyon yönleri seçilebilir.</p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Artık kısa bir kaç test yapılabilir. İlk olarak istemci uygulama çalıştırıldığında Kitap tablosunun tüm içeriğinin çekildiği gözlemlenecektir. Burada tüm verinin indirilmesi son derece normaldir. Program çalıştıktan sonra örneğin, istemci tarafındaki veri içeriğinde çeşitli değişiklikler yaptığımızı varsayalım. Örneğin KitapId alanının değeri 4 olan satırı sildiğimizi, yeni bir kitap eklediğimizi ve 83 numaralı kitabın adı için bir güncelleştirme yaptığımızı düşünelim.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_16.gif" alt="" width="595" height="333" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bu işlemlerin arkasından değişiklikleri <strong>DataSet</strong> üzerinde kaydedip <strong>Senkronize</strong> <strong>Et</strong> düğmesine basarsak, farklılıkların sunucu tarafınada aktarıldığını görebiliriz. Bu noktada özellikle <strong>LastEditDate</strong> ve <strong>CreationDate</strong> alanlarının istemci ve sunucudaki değerleri farklılıkların tespitini kolaylaştırmaktadır. Bunu daha rahat görebilmek amacıyla Azon.sdf dosyası içerisindeki Kitap tablosu ile sunucudaki Azon veritabanında yer alan Kitap tablosunun içeriklerini karşılaştırmanızı öneririm.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_17.gif" alt="" width="636" height="197" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Yeni kayıt ekleme ve güncelleme işlemleri dışında istemci tarafında birde satır silmiştik. Bu nedenle sunucu veritabanındaki <strong>Kitap_Tombstone</strong> tablosunda aşağıdaki şekildende anlaşılacağı üzere 4 numaralı satır(Silinen kitabın KitapId değeri) için bir ekleme yapıldığı gözlemlenebilir.</span></span></p>
<p><span style="font-size: small;"><img src="/makale/images/mk265_18.gif" alt="" width="245" height="88" border="0" /></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">İkinci test olarak sunucu üzerinde değişikliker yapıp bunları istemci tarafına, uygulamadaki <strong>Senkronize Et</strong> düğmesini kullanarak alabiliriz. Şu nokta unutulmamalıdır; Senkronize etme işlemi program her açıldığında <span style="text-decoration: underline;">yapılmamaktadır</span>. Nitekim veritabanında değişiklik yapılsa ve istemci ile sunucu arasında bir bağlantı olmasa bile, istemci uygulama yerel veritabanı(Local Database-sdf) üzerindeki veriler ile çalışarak, değişiklikler, eklemeler ve silmeler yapabilir ama, senkronize etme işlemi başlamadığı sürece hem değişiklikleri alamaz hem de bunları sunucu veritabanına iletemez.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;">Bir açıdan bakıldığında, yapılan işlemler verilerin normal yollarla karşılıklı olarak uç kaynaklara gönderilmesinden pek farklı değildir. Özellikle bağlantısız katman modelinde geliştirme yapıldığında benzer işlevsellikleri sağlayabiliriz. Ne varki <strong>Sync Services for Ado.Net</strong> alt yapısı sunucu ve istemci tarafındaki senkronizasyonun sağlanması adına geliştiriciye daha güçlü ve yönetilebilir tipler sunmaktadır. Ayrıca senkronize işlemlerinin yapılması sırasında sunucu veri kaynağının sabit bir <strong>SQL</strong> veritabanı olması şartı bulunmamakla birlikte, <strong>N-Tier</strong> yada <strong>SOA</strong> tabanlı geliştirme yapmakta mümkündür. Bu açılardan bakıldığında avantajlar ortadadır. </span></span><span style="font-size: small;"><span style="font-family: Verdana;">Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşünceye dek hepinize mutlu günler dilerim.</span></span></p>
<p><span style="font-size: small;"><span style="font-family: Verdana;"><a href="https://buraksenyurt.com/makale/images/AzonSync.rar">Örneği İndirmek İçin Tıklayın</a></span></span></p>2009-01-03T10:00:00+00:00ado.netsync serviceswcfbsenyurtBirbirleri ile sürekli bağlantı halinde olamayan istemci/sunucu(Client/Server) mimarilerinde en büyük problemlerden biriside verilerin karşılıklı veya tek taraflı olaraktan senkronize edilmeleridir. Çoğu büyük çaplı saha uygulamasında, sunucu tarafındaki veri kaynaklarının istemcide kullanıldığı durumlar söz konusudur. Bu noktada istemcilerin sürekli bağlı kalamadıkları bir ortamın var olması olasıdır (Occasionally Connected Enivronments).https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=ec57f52c-1d4a-40b2-9bf7-a317ab662a7c3https://buraksenyurt.com/trackback.axd?id=ec57f52c-1d4a-40b2-9bf7-a317ab662a7chttps://buraksenyurt.com/post/Ado-Net-Senkronizasyon-Servisleri(Sync-Services-for-Ado-Net)-bsenyurt-com-dan#commenthttps://buraksenyurt.com/syndication.axd?post=ec57f52c-1d4a-40b2-9bf7-a317ab662a7c