Bolu-Abant ve Kayseri Gezileri

Geçtiğimiz hafta yıllık iznim sebebiyle İstanbul dışındaydım. İznimin ilk 4 gününü Bolu-Abant’ta eşsiz doğa manzarası ile geçirdim. Sonrasında Ankara’da 1 gün kalıp buradan da çok sevdiğim bir arkadaşımın düğünü için Kayseri’ye geçtim. Abant ve Kayseri’ye ilk kez gittim ve buralardaki izlenimlerimle ilgili kısa bir gezi yazısı yazmaya karar verdim. Sanırım blogumun ilk gezi yazısı bu, hadi okuyun bakalım :)

 

Bolu-Abant Gezisi

Pazartesi günü erken saatlerde Bolu’nun yollarını tuttuk. Abant Gölü’ne gitmek için İstanbul-Bolu yolunda Bolu girişindeki Abant sapağına dönmeniz ve bu istikamette yaklaşık 20 km. ilerlemeniz gerekiyor. Özellikle göle yaklaştığınızda yolun biraz bozulmaya başladığını ve buralardan dikkatle geçmeniz gerektiğini belirtmemde fayda var. Yine Bolu’nun merkezinden belirli aralıklarla(2 saatte 1 sefer oluyor sanırsam) kalkan otobüslerle de Abant Gölü’ne ulaşmanız mümkün. Gölün hemen kenarında yer alan iki tane 5 yıldızlı otelin olduğunu söylemekte fayda var. Gölün 5-6 km. gerisinde ise birçok pansiyonun olduğunu da belirtmek isterim.

Öğlen saatlerinde Abant Gölü’nün karşısında oldukça güzel bir konumda yer alan Abant Palace Otel’e geldik ve hemen odamıza yerleştik. İlk gün hava biraz kapalı ve sisli olduğu için manzara açısından pek tatmin edici bir görüntü göremedik odamızdan. Ancak Salı sabahının ilk ışıkları ile karşılaştığımız manzara gerçekten harikaydı. Kahvaltımızı yaptıktan sonra soluğu göl kenarında aldık. Sazlıklar arasındaki nilüfer çiçekleri ve minik ördek yavruları karşılıyor burada sizleri. Sonrasında alabildiğince güzel bir göl manzarası ve dağ yamacındaki çam ağaçları... Abant Gölü’nün bir diğer özelliği buranın su samurlarının doğal yaşama sahası olması. Abant’a daha önceden giden arkadaşlarım burada su samurları gördüklerini söylemiştiler ama biz görebilme şansına nail olamadık. Göl kenarında açık havada sakin ve sessiz bir ortamda yürüyüş yapmak, o temiz havayı solumak özellikle büyük şehirlerin yoğun temposundan uzaklaşmak ve dinlenmek için gerçekten birebir. Gölü faytonlarla veya otelden kiralayacağınız bisikletlerle gezebilmeniz mümkün. Yine göl kenarında yer alan atların sırtında kendiniz göl kenarında gezebilme şansına sahipsiniz. Bu arada, buradaki her iki otelin de en ilginç yönlerinden birisi konuklarının çoğunluğunun Arap turistlerden oluşmasıydı. Öyleki kendinizi yabancı bir ülkede sanacak kadar çok Arap turist vardı.

Bolu’dan ayrılmadan önceki gün ise Bolu’nun merkezini gezdik. Bolu, küçük ve şirin bir şehir merkezine sahip. Şehrin neresine bakarsanız bakın İzzet Baysal’ın ve Köroğlu’nun izlerini görebiliyorsunuz. 7-8 sene önce yine Bolu’yu gezme şansı bulmuştum ve gözlemlerime göre bu süre zarfı içerisinde şehir merkezi oldukça gelişmiş. Aslına bakarsanız şehir merkezinde gezilebilecek çok fazla tarihi veya ilgi çekici yer yok. Merkezde yer alan camiler ve Köroğlu heykelinin biraz ilerisinde yer alan küçük kitapçılar çarşısı gezilebilecek yerler. Gezmekten ziyade Bolu’ya gittiğinizde bol bol lokanta gezmenizi ve farklı yemekleri tatmanızı tavsiye edebilirim aslında. Bunun dışında Gölcük ve Yedi Göller bölgesi de Bolu’da gezilmeye değer yerler, tabi yeterli süreyi bulup buralara gitmeye fırsat bulabilirseniz...

Otel odasından Abant Gölü 
Otel odasından gölün görünümü

Abant Gölü 
Göl kenarından bir manzara

 

Kayseri Gezisi

Otelden ayrıldıktan sonra Ankara’ya gitmek için yola çıktık. Ankara’da bir gün kalıp buradan arkadaşlarımla beraber Kayseri’nin yollarına düştük. Kayseri’ye giderken Kırşehir’in Mucur ilçesinde mola verip birşeyler atıştırdık. Eğer yolunuz buradan geçerse yol kenarındaki küçük bir restorantta “Soğanlama” adı verilen yöresel gözlemeden yemenizi tavsiye ederim. Kayseri’ye değerli arkadaşlarım Oğuz ve Ayşegül Özkavukçu’nun düğünleri için gitmiştik aslında, ama hazır Kayseri’ye gitmişiz gezmeden döner miyiz! Cumartesi günü Kayseri’de güzel bir şehir turuna çıktık. İlk olarak Talas’ta Kayseri merkezini oldukça yüksekten ve çok güzel gören bir mekanda sabah kahvaltımızı yaptık. Sonrasında şehir merkezinde birkaç saatlik gezimiz oldu. Mantısı, yağlaması ve pastırması ile bu meşhur şehirde bu tatların lezzetine bakmamak olmazdı tabi ki. “Ananın Yeri” isimli meşhur restorantta mantımızı yedik, partırmacıların bulunduğu çarşıdan da pastırmalarımızı satın aldıktan sonra tekrar Ankara yollarına düştük. Kayserili birçok arkadaşımdan bu şehrin oldukça büyük ve gelişmiş olduğunu hep duyardım. Ancak gidip görene kadar bu kadar büyük ve harika bir şehir olduğunu tahmin edememişim. Gerçekten çok gelişmiş ve oldukça modern bir şehir Kayseri. Şehir merkezinde birçok modern yapının yanıbaşında tarihi medrese, cami, kilise, anıt, kale gibi mekanları görebilmeniz mümkün. Eğer yolunuz bu taraflara düşerse mutlaka Kayseri’ye uğramanızı ve en azından şehir turu atıp bu güzel şehri görmenizi tavsiye ederim.

Kayseri’de zamanımız biraz kısıtlı olduğu için pek fotoğraf çekme şansım olmadı, ama çektiğim birkaç kareyi de aşağıda bulabilirsiniz.

Talas'tan Kayseri
Talas’tan Kayseri Manzarası. Resmin sol kısmında yer alan yerleşim birimi eski bir Ermeni köyüymüş


Kayseri’nin merkezinden bir kare

 
“Kuş gömü pastırma” adı verilen tür pastırmaların en iyisi ve lezzetlisi oluyormuş. Gerçekten de öyleydi. Ama çok fazla yememenizi tavsiye ederim. Sonra 2 gün boyunca üzerinizden kokusu çıkmıyor:) Bu arada tüm Kayserili arkadaşlarım İmamoğlu isimli bir markayı tavsiye ettiler, en iyi pastırma İmamoğlu’ndadır dediler(Reklam oldu biraz ama)

30 Temmuz 2009 Perşembe 09:18

Yorum - RSSYorumlar (6)

Etiket: ,
Kategori: Kişisel

facebook'da Paylaş   twitter'da Paylaş   friendfeed'de Paylaş   del.icio.us'da Paylaş   stumpleupon'da Paylaş   Permalink

GridView – Silme ve Güncelleme İşlemlerindeki Hataları Yönetmek

Bildiğimiz gibi GridView kontrolünü DataSource kontrolleri aracılığıyla veriye bağladığınızda eğer istenirse Update ve Delete sorguları da oluşturulabiliyor. Bu sorgulardan yola çıkarak tek satır dahi kod yazmadan listelenen kayıtlar üzerinde güncelleme ve silme işlemleri yapabiliyoruz. Herşeyin otomatik olduğu böyle bir ortamda bazen hesapta olmayan(aslında veritabanı tasarımında hesaplanan, yani aslında hesapta olması gereken) sorunlarla da karşılaşabiliyoruz. Ne gibi sorunlar derseniz; örneğin listelediğimiz kayıtlardan bir tanesini silmek istediğimizde eğer farklı bir tabloda bu kayıda bağlı başka satırlar varsa(constraint ile silinmesi kısıtlanmışsa) silme işlemi hataya yol açacaktır. Yine güncelleyeceğiniz satırın bir alanına hatalı bir veri girişi yaparsak(null değer almayan bir alanı boş bırakmak gibi) başka bir hata ile karşılaşırız. Bu tip durumlarda iki farklı çıktı ile karşılaşabiliriz, eğer özel hata sayfalarını aktifleştirmemiş ve debug modda çalışmayı kapatmadıysak doğrudan üretilen SqlException tipindeki hata mesajını, ya da özel hata sayfalarını aktifleştirdiysek hata sayfamıza yönlendiriliriz. İlk durumdaki hata çıktısı eminim ki sizlere pek yabancı gelmeyecektir(buyrun resime bakalım)

Bu sayfadan özel hata sayfalarını aktifleştirirsek kurtulabiliriz. Ancak bu hata sayfaları projemizin genelinde görüntüleneceği için GridView’da oluşan hatalar için kendimiz farklı bir hata sayfası tasarlamak isteyebiliriz. Böylece burada alınan SqlExcpetion tipindeki hatayı kullanıcıya görüntüleyerek ne tarz bir hata yapıldığı konusunda daha doyurucu bir bilgi sunabiliriz. GridView üzerinde bir işlem yapılırken çalışma zamanında oluşan bir hatayı yakalamak istiyorsak sayfamızın Error eventi için yazılabilecek Page_Error metodunu kullanabilir veya yine sayfada yer alan OnError isimli virtual metodu ezebiliriz(override edebiliriz). Aklımıza, GridView’ın kendine özel bir hata eventi yok mudur sorusu gelebilir, cevabını hemen vereyim maalesef yoktur:) O zaman parmaklarımızı hazırlıyoruz ve klavyemizden aşağıdaki sihirli kodları yazıp neler olacağına göz atıyoruz.

Default.aspx (RowDeleting ve RowUpdating eventlerini metotlarına bağlıyoruz)

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"

    DataKeyNames="ProductID" DataSourceID="SqlDataSource1"

    onrowdeleting="GridView1_RowDeleting" onrowupdating="GridView1_RowUpdating">


Default.aspx.cs

private string command; //Islem tipini saklamak icin

 

//Sayfada hata olustugunda OnError metodu tetiklenir

protected override void OnError(EventArgs e)

{

    base.OnError(e);

 

    //Olusan son hatanin mesaj bilgisini aliyoruz

    string errorMessage = Server.GetLastError().Message;

    if (command == "Delete")

        Session["gridHata"] = "Silme işleminde hata! Hata mesajı: " + errorMessage;

    else if (command == "Update")

        Session["gridHata"] = "Güncelleme işleminde hata! Hata mesajı: " + errorMessage;

    Server.Transfer("Hata.aspx");

}

protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)

{

    //Islemin tipini Delete olarak belirleyip Session'a null degerini atiyoruz

    //Silme islemi basarili olursa Session'daki deger silinecek

    command = "Delete";

    Session["gridHata"] = null;

}

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)

{

    //Islemin tipini Update olarak belirleyip Session'a null degerini atiyoruz

    //Guncelleme islemi basarili olursa Session'daki deger silinecek

    command = "Update";

    Session["gridHata"] = null;

}

 

Neler yaptığımızı özetleyecek olursak; GridView1_RowDeleting ve GridView1_RowUpdating metotlarında yapılan işlemin tipini saklayıp Session nesnesinin içeriğini boşalttık. Ezdiğimiz OnError metodunda ise oluşan hatanın mesajını alıp Session’a kaydettik, ardından da talebi Hata.aspx adındaki bu iş için oluşturacağımız hata sayfasına yönlendirdik(Server.Transfer ile yönlendirmemizin sebebi URL satırında hala Default.aspx’in saklı kalmasını sağlamak. Çok kritik bir durum değil, Response.Redirect ile de yönlendirme yapılabilir) Hata.aspx sayfamızın da Page_Load metodunda Session bilgisine bakarak ekrana hatayı yazdırdığımızda artık senaryomuz çalışır hale gelecektir.

Hata.aspx

protected void Page_Load(object sender, EventArgs e)

{

    if (Session["gridHata"] != null)

        Response.Write(Session["gridHata"].ToString());

 

    Session["gridHata"] = null;

}

10 Temmuz 2009 Cuma 23:36

Yorum - RSSYorumlar (1)

Kategori: ASP.NET

facebook'da Paylaş   twitter'da Paylaş   friendfeed'de Paylaş   del.icio.us'da Paylaş   stumpleupon'da Paylaş   Permalink

LINQ to SQL’de Bulk Delete İşlemleri

LINQ to SQL’in temel hedef noktası projelerdeki Select işlemleridir. Tabi ki bunun yanında diğer CRUD işlemleri olan Insert, Update ve Delete sorguları da DataContext nesneleri üzerinden gerçekleştirilebiir. Bu işlemlerle ilgili daha önceden yazdığım blog girdimi bu linkten okuyabilirsiniz. Bu yazımda LINQ to SQL yapısı dahilinde veritabanında çalıştıracağımız Bulk Delete(birden fazla kaydı etkileyen delete işlemleri diyelim) işlemlerini inceleyeceğiz. Eğer daha önceden LINQ to SQL’de yaptığınız delete işlemlerini SQL Profiler’dan gözlemlemediyseniz yazımızın ilerleyen kısımlarında(hatta hemen devamında) ilginç bir detayla karşılaşacaksınız.

Öncelikli olarak LINQ to SQL üzerinde basit bir delete işlemi için gerekli kodları yazalım ve SQL Profiler’da bizi nasıl bir süpriz bekliyormuş görelim. Northwind veritabanındaki Product tablosunu içeren bir LINQ to SQL sınıfı(.dbml dosyası) oluşturuyor ve basit bir konsol uygulaması üzerinden CategoryID değeri 10 olan ürünleri siliyorum(Veritabanında Id değeri 10 olan bir kategori yok, eğer Constraint’lere takılmadan bu örneği yazmak istiyorsanız yeni bir kategori ve bu kategoriye ait birkaç ürünü Product tablosuna eklemenizi tavsiye ederim).

Program.cs

NorthwindDataContext ctx = new NorthwindDataContext();

var p = from urun in ctx.Products

        where urun.CategoryID == 10

        select urun;

 

ctx.Products.DeleteAllOnSubmit(p);

ctx.SubmitChanges();

Şu an üzerinde çalıştığım tabloda 10 numaralı kategoriye ait 4 tane kayıt var. Uygulamayı çalıştırıp SQL Profiler’dan sorguların çalıştığını nasıl izliyoruz.

Sonuç biraz enteresan olsa da temel olarak Select sorguları için hazırlanmış bir ortamın bundan daha fazlasını yapması beklenmez sanırım:) Şekile bakıp da hala nedir burada enteresan olan diye soranlarınız varsa; 4 tane farklı delete sorgusunun çalışmasıdır enteresan olan. Böyle bir işlem sonucunda çoğumuz arka planda Delete From Products Where CategoryID=10 gibi bir sorgunun çalışmasını bekleriz, çünkü veriye erişimi biz yazdığımız zaman delete sorgumuz böyle olacaktır. Ama unutmamak lazım ki artık biz yazmıyoruz! LINQ to SQL bu tarz bir delete ifadesini arka planda her bir satırı etkileyecek şekilde tasarlar ve SQL Server’a gönderir. Dolayısıyla aynı anda yüzlerce-binlerce kayıdı etkileyecek delete işlemi yapıyorsak, resimde gördüğümüz çıktı bizi performans kuşkularına düşürebilir. Hem satırların tek tek silinmesi, hem de network trafiği açısından bu kadar sorgunun taşınması sorun oluşturabilir. O zaman bu durumu iyileştirmek için nasıl bir yol izlemek lazım?

Bu sorunun cevabını bulmak için ben yaklaşık 3 saatimi harcadım. İlk olarak DataContext nesnesi içerisinde işe yarayacak bir üye aradım ama nafile. Ardından inatla kendim çözeceğim diye yola koyulup işe yarar birşeyler çıkaramayınca, 3 saatin sonunda dünyayı yeniden keşfetme inadımdan vazgeçip arama motorlarının yollarını tuttum. Bu linkten orjinaline ulaşabileceğiniz yazıda gayet güzel ve basit bir metot ile bu işin üstesinden gelinmiş(Yazanın ellerine sağlık). Aşağıda bu metodu görebilirsiniz. Metodu extension metot olarak uygulayacağımız için DataContext’ten eriştiğimiz Table nesneleri üzerinden çağırmamız daha kolay olacak. Metotla ilgili açıklamaları ilgili satırlara yorum olarak ekliyorum.

TableExtensions.cs

public static class TableExtensions

{

    //DataContext'te yer alan Table<TEntity> nesneleri uzerinden cagrilabilmesi icin Extension Method olusturuyoruz

    public static int BulkDelete<TEntity>(this Table<TEntity> table, IQueryable idsToDelete) where TEntity : class

    {

        //Uzerinde sorgu calistirilacak tablonun metadata bilgileri cekiliyor

        MetaTable metaTable = table.Context.Mapping.GetTable(typeof(TEntity));

        string tableName = metaTable.TableName;

 

        //Bu arada bulk delete metodumuz sadece bir tane PK kolonu tasiyan tablolarda kullanilabilir!

        if (metaTable.RowType.IdentityMembers.Count != 1)

        {

            var keyFields = from im in metaTable.RowType.IdentityMembers

                            select im.MappedName;

 

            if (keyFields == null || keyFields.Count() < 1)

            {

                keyFields = new List<string>();

            }

            //Eger tabloda birden fazla PK varsa Exception firlatiliyor

            throw new ApplicationException(string.Format("Error in TableExtensions.BulkDelete<TEntity>: Table {0} has a compound key.  BulkDelete can only operate on tables with a single key field.  (key fields found: {1}", tableName, string.Join(",", keyFields.ToArray())));

        }

        string primaryKey = metaTable.RowType.IdentityMembers[0].MappedName; //PK kolonu bulduk

 

        System.Data.Common.DbCommand origCmd = table.Context.GetCommand(idsToDelete);

        string toDelete = origCmd.CommandText;

        //Iste bu kisimda Delete sorgusu olusturuluyor ve

        //subquery ile Select cumlesinden donen kayitlar Delete ifadesine dahil ediliyor

        string sql = string.Format("delete from {0} where {1} in ({2})", tableName, primaryKey, toDelete);

 

        origCmd.CommandText = sql;

 

        bool openedConn = false;

 

        //Baglanti acma-kapama ve sorgunu calismasi islemleri burada yapiliyor

        if (origCmd.Connection.State != ConnectionState.Open)

        {

            openedConn = true;

            origCmd.Connection.Open();

        }

 

        try

        {

            //Sorgu burada dogrudan calistiriliyor. Dolayisiyla bu metotdan sonra

            //DataContext.SubmitChanges() metodunu cagirmaya gerek kalmiyor

            return origCmd.ExecuteNonQuery();

        }

        finally

        {

            if (openedConn)

            {

                origCmd.Connection.Close();

            }

        }

    }

}

Metot DataContext nesnemiz içerisinde yer alan entity tablolarımız için hazırlanmış bir extension metottur. Yani projemizin herhangi bir yerinden DataContext.TabloIsmi.BulkDelete() şeklinde çağrılabilir. Parametre olarakta sorgulanabilir bir koleksiyon alıyor, yani LINQ sorgumuzun sonucu parametre olarak bu metoda gönderilecek. Metot içerisinde ele alınan entity tablosunun yapısı çözümlenerek tablo ismi ve primary key kolonu elde ediliyor. Böylece DELETE FROM TabloAdi WHERE PrimayKeyKolonu IN (Silinecek satırların PK değerleri) şeklindeki bir sorguyu hazırlamamız mümkün olacaktır. Dikkat ettiyseniz buradaki sorgu sayesinde tüm delete işlemlerini tek bir sorgu ile yapabileceğiz.

Metot ile ilgili bir diğer dikkat edilmesi gereken nokta ise yukarıda koyu puntolarla yazdığım DELETE ifadesinin sonunda yer alan subquery’nin döndüreceği değerler. Sorguyu biraz daha açacak olursak; burada incelediğimiz Product tablosu için DELETE FROM Product WHERE ProductID IN (SELECT ProductID FROM Product WHERE …) şeklinde bir sorgumuz olmalı. Yani subquery olarak saklanan SELECT sorgusu geriye sadece primary key kolonun değerlerinden oluşan satırları döndürmelidir. O zaman BulkDelete metoduna bir LINQ sorgusundan gelen tüm bilgileri değil de sadece primary key kolonundan oluşan kümeyi göndermemiz gerekecektir. İzah etmek istediğim bu durum anlaşılmadıysa aşağıdaki kod parçalarını dikkatlice incelemenizi tavsiye edeceğim.

Program.cs

NorthwindDataContext ctx = new NorthwindDataContext();

var p = from urun in ctx.Products

        where urun.CategoryID == 10

        select urun;

 

//BulkDelete metoduna sadece PK kolonundaki bilgileri gondermemiz gerekecegi icin

//sorgu sonucundaki var degiskeninin sadece ProductID alanini seciyoruz

ctx.Products.BulkDelete(p.Select(pr => pr.ProductID));

 

Görüldüğü gibi Lambda ifadesi kullanılarak LINQ sorgusu sonucunda gelmesi beklenen kayıtların sadece ProductID bilgilerini metoda gönderdik. Yine dikkat çekmek istediğim bir nokta da bu sorgulama sonunda ctx nesnesinin SubmitChanges metodunu çağırmamıza gerek olmadığıdır. Çünkü extension metot içerisinde yeni bir sorgu nesnesi oluşturulup bunun çalıştırılması sağlanıyor ve DataContext nesnesi üzerinden ek bir işlem daha yapmamıza gerek kalmıyor. Metodun çalışması sonucunda SQL Server’a gönderilecek bilgileri SQL Profiler adlı aracımızdan izlediğimizde aşağıdaki gibi bir sonuçla karşılaşacağız.

Ekran çıktısında da görüleceği gibi SQL Server’a gönderilen sorgu sayısı artık bire inmiş durumda. Eğer LINQ to SQL kullandığınız projelerinizde aynı anda çok fazla sayıda kayıt silmek gibi bir ihtiyacınız olursa böyle bir metot işinizi görecektir.

5 Temmuz 2009 Pazar 23:13

Yorum - RSSYorumlar (0)

Etiket: ,
Kategori: .NET Framework | C#

facebook'da Paylaş   twitter'da Paylaş   friendfeed'de Paylaş   del.icio.us'da Paylaş   stumpleupon'da Paylaş   Permalink

Windows 7 ile 7 Saat

windows7_logo Tüm zamanların en iyi işletim sistemi Windows 7’nin RTM sürümünün çıkmasına çok az süre kaldı. Windows 7 ile gelen yeniliklere BT Uzmanı veya Yazılım Geliştirici gözüyle bakmak istiyorsanız 11 Temmuz 2009 Cumartesi günü Microsoft Türkiye’nin İstanbul ofisinde gerçekleşecek paralel 14 oturum sizleri bekliyor.

INETA Türkiye’nin düzenlediği bu etkinliğe katılmak için www.inetatr.org adresinden kayıt olabilirsiniz.

 

1 Temmuz 2009 Çarşamba 21:10

Yorum - RSSYorumlar (3)

Etiket: ,
Kategori: Duyuru-Haber

facebook'da Paylaş   twitter'da Paylaş   friendfeed'de Paylaş   del.icio.us'da Paylaş   stumpleupon'da Paylaş   Permalink

Bağlantılar



Takip Et

RSS Feed twitter friendfeed

Seminer/Webiner Programım

  • Seminer-WebinerASP.NET 4.0 WebForms Yenilikleri (Microsoft İstanbul Ofisi)
    29 Mayıs 2010

  • Seminer-WebinerVisual Studio 2010 Yenilikleri (Osmangazi Üniversitesi)
    15 Mayıs 2010

  • Seminer-WebinerASP.NET AJAX ile Zengin Internet Uygulamaları Geliştirme (Microsoft İstanbul Ofisi)
    3 Mayıs 2010

>> Etkinlik Takvimi