Table Services Round 2

0 dakikada yazıldı

24402 defa okundu

Düzenle

[Aşağıdaki makalenin SDK2.5 ile beraber yeni Azure özelliklerine uygun
şekilde güncellenmiş halini
burada
bulabilirsiniz.]

Konuyla ilgili bir önceki yazı; Azure Storage Table
Services

Table Services ile bir önceki yazıda bazı konuları bir sonraki :) yazıya
yani bugüne bırakmıştık. Gelin şimdi kaldığımız yerden devam edelim.

Table Service ile uğraşırken relation desteğinin olmadığından ve aslında
bunun da en büyük farklılıklardan biri olduğundan bahsetmiştik. Hatta
eğer ki kuvvetli bir relational yapıya ihtiyacınız varsa tabi ki SQL
Azure tarafına doğru kaymanız gerektiğini de söylemiştik :) Amma :) tabi
ki mini relationlarla ilgili ilginç çözümler uygulayabiliriz. Bu ilginç
çözümleri uygularken de isteyeceğimiz bir diğer şey Entity Group
Transaction'ların mantıksal relation yapımızda kullanılabiliyor olması.
Biliyorsunuz EGT'ler sadece aynı table ve aynı partition içerisinde olan
nesneler arasında kullanılabiliyordu. Peki bir relational iki farklı
nesneyi nasıl olur da aynı partition ve aynı table'da tutarız?

Çözüm basit!

Gerçekten basit :) Çünkü birincisi Table Services'daki her table'ın
şeması tamamen esnek. Yani bir table yaratırken şema vermediğimiz gibi
sonradan bir table'a istediğimiz kadar farklı şemada farklı nesneler
koyabiliyoruz. Önemli olan tek birşey var, tüm nesnelerin kesinlikle
PartitionKey, RowKey ve TimeStamp'i olmalı. Peki iki farklı nesneyi
nasıl tek tabloda tutarız? Tabi ki aynı tabloyu hedefleyen iki farklı
Context ile ;)

[C#]

public class Urun : TableServiceEntity
{
    public string Adi { get; set; }
    public string Aciklama { get; set; }
}
public class UrunDetay : TableServiceEntity
{
    public string DetayMetin { get; set; }
}

İlk olarak yukarıdaki gibi iki farklı nesnemiz olduğunu ve bu nesnelerin
aslında birbirleri ile ilişkide olacaklarını varysalaım. Yeni özünde her
ürünün bir UrunDetay nesnesinin olacağını varsayıyoruz. Nesneleri
yukarıdaki şekilde tanımladıktan sonra bu nesneler için ayrı ayrı birer
de ServiceContext tanımlıyoruz.

[C# / UrunlerContext]

public class UrunlerContext : TableServiceContext
{
    private static CloudStorageAccount storageAccount =
    CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
    public UrunlerContext()
        : base(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials)
    {
    }
    public DataServiceQuery<WebRole1.Entities.Urun> Urunler
    {
        get
        {
            return CreateQuery<WebRole1.Entities.Urun>("Urunler");
        }
    }
}

[C# / UrunDetayContext]

public class UrunDetayContext : TableServiceContext
{
    private static CloudStorageAccount storageAccount =
    CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
    public UrunDetayContext()
        : base(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials)
    {
    }
    public DataServiceQuery<WebRole1.Entities.UrunDetay> UrunlerDetaylar
    {
        get
        {
            return CreateQuery<WebRole1.Entities.UrunDetay>("Urunler");
        }
    }
}

Gördüğünüz gibi her iki context'de doğrudan "Urunler" tablosunu
hedefliyor. Bu iki context'e birden INSERT yapmak istersek aşağıdaki
gibi bir kod kullanabiliriz tabi ki.

[C#]

var urunlerContext = new UrunlerContext();
var yeniUrun = new Entities.Urun
{
    PartitionKey = "Musteri1",
    RowKey = "Ürün1",
    Adi = "Deneme",
    Aciklama = "Açıklama"
};
urunlerContext.AddObject("Urunler", yeniUrun);
urunlerContext.SaveChanges();

var urunDetaylarContext = new UrunDetayContext();
var yeniDetay = new Entities.UrunDetay
{
    DetayMetin = "Deneme",
    PartitionKey = "Musteri1",
    RowKey = "detay_Ürün1"
};
urunDetaylarContext.AddObject("Urunler", yeniDetay);
urunDetaylarContext.SaveChanges();

Durum çok basit değil mi? Artık tabloda iki farklı şemada iki farklı
nesne var. Bu noktada düşünmemiz gereken birkaç şey var :) Birincisi bir
tabloya PartitionKey, RowKey harici bir sorgu gönderirsek ne olacak?
Yani "where" kısmında "DetayMetin" ile ilgili araması olan bir sorgu
gönderirsem aynı tabloda bütün Urun nesneleri de gezilecek mi? Oysa
Urun'lerin böyle bir özelliği yok. İşte tam da bu sorunu çözmek ve aynı
tablodaki bu iki farklı nesne tipini birbirinden rahat bir şekilde ayırt
edebilmek için .... RowKey'e dikkat :) Aslında iki nesne arasındaki
ilişkiyi de RowKey üzerinde tutmuş durumdayım. İlk nesnenin RowKey
değerini alıp önüne bir "preFix" ekleyip UrunDetay nesnesinin RowKey'ine
verdim. Böylece rahatlıkla istediğimiz zaman bir detay bilgisi almak
istediğimizde ana nesnenin RowKey'inin başına "detay_" ekleyerek ikinci
bir sorguyla da detayını alabiliriz ;)

[C#]

var urunDetaylarContext = new UrunDetayContext();
var urunlerContext = new UrunlerContext();

var ArananUrunKey = "Ürün1";
var AnaUrun = urunlerContext.Urunler.AsTableServiceQuery()
              .Where(c => c.RowKey == ArananUrunKey 
                       && c.PartitionKey == "Musteri1");
var Sonuc = urunDetaylarContext.UrunlerDetaylar.AsTableServiceQuery()
              .Where(c => c.RowKey == string.Format("detay_{0}", ArananUrunKey) 
              && c.PartitionKey == "Musteri1");

Görüşmek üzere!

Konunun devamı için; Table Services Round 3 : Continuation
Token