Makale Özeti

Data Access Layer için manüel kodlama yapar mısınız? Yapıyorsanız hep aynı kodları yazmaktan sıkılmadınız mı ? Typed DataSet'ler üzerinde TypedDataSetGenerator ile çok kolay bir şekilde veri tabanı üzerindeki Store Procedure, Table, View gibi nesnelere ulaşıp gerekli olan kod bloğunu üretebilirsiniz.Peki, Oracle üzerinde Typed DataSet için 'minimum kodlama ile' Data Access Layer nasıl olur?

Makale

Generic Oracle DataAccess Layer + Typed DataSet

      Demo burada :)  

Data Access Layer için manüel kodlama yapar mısınız? Yapıyorsanız hep aynı kodları yazmaktan sıkılmadınız  mı ? :) (Bulduğunuz çözüm Code Generator yazmak mıdır? Dilin nimetlerinden yararlanın derim.) SQL Server ortamında Data Access Layer için en rahat çözüm tabii ki Typed DataSet yani XSD dosyalarıdır. Typed DataSet'ler üzerinde TypedDataSetGenerator ile çok kolay bir şekilde veri tabanı üzerindeki Store Procedure, Table, View gibi nesnelere ulaşıp gerekli olan kod bloğunu üretebilirsiniz. Nasıl yapılacağını buradan öğrenebilirsiniz. 

SQL Server platformunda Typed DataSet kullanmaya alışmış ve tüm alt yapısını SQL Server üzerine kuran bir yazılımcı Oracle Platformuna geçince ne olur? Bir süre sudan cıkmış balık durumda kalır. :) En büyük veri tabanı üreticilerinden biri olan Oracle'ın .Net platformu için SQL Server kadar hızlı ve kolay bütünleşik bir kod geliştirme aracı ne yazık ki yok. VS içinde ki Server Explorer penceresinden Oracle Packet içeriklerini bile göremiyorsunuz. Odp.Net ile gelen Oracle Explorer penceresi ile ancak Oracle veri tabanınızın detaylarını görebilmektesiniz. Fakat el alışkanlığı ile burada ki nesleri sürükleyip Xsd dosyanıza bırakmak istediğinizde nesnelerin taşınamaz olduğunu görürsünüz. Google'da Oracle Typed DataSet üzerine derin araştırmalar yapıp en sonunda Oracle XSD dosyalarını bir sonra ki VS sürümünde destekleyeceğini açıklayan duyurusu ile tüm hayalleriniz yıkılır. Ama iş beklemez çözüm bulunmalı. Peki, Oracle üzerinde Typed DataSet için 'minimum kodlama ile' Data Access Layer nasıl olacak ki?

Önce DataAccesss Layer nasıl olacak? Typed DataSet kullanan programlarda çalışma mantığı: Veriyi çek, kullanıcıya işlettir ve veri tabanını System.Data.DataAdapter sınıfı ile güncelle şeklindedir. Typed Data Set kullanıyorsanız DataAccess Layer System.Data.DataAdapter nesnesinin bir uygulamasını içermek zorundadır. SQL platformunda bunu TypedDataSetGenerator yaptığı için problem yok. Oracle platformu için çözüm üretelim:

İş ihtiyacımız nedir? Oracle Packetler içinde olan Store Procedure'leri kendi projemiz içinde çağırabilmek ve Typed DataSet üzerinde kullanmak. (Zaten diğer Oracle nesnelerine VS içinden erişilmekte.) Tüm bunları sürekli aynı kodları tekrar etmeden yapmalıyız.

Çözüm: Kod tekrarı yapmamak için Generic Data Access Layer oluşturmak.  İhtiyacımız olan tüm Store Procedure'leri Typed DataTable sınıflarına attribute olarak atamak ve Generic Data Access Layer üzerinde bu attributeleri kullanarak gerekli işlemleri yerine getirmek.(Bir önceki konuda olduğu gibi bu konuda da Attribute sınıflar yardıma koşuyor.) Her zaman ki gibi kodu en üst seviyede yazmalıyız. Sürekli kendisini tekrar eden kodlama yerine en üst seviyede bir defa kod yazmak. Böylece DataAdapter nesnesine olan bağımlılı tek yerden ve kesin bir şekilde ortadan kaldırabiliriz. 

Önce Store Procedure'leri tanımlayacağımız Attributeleri yazalım:

 

 Store Procedure Attribute sınıflarımızı Typed DataTable sınıflarımıza ekleyelim.

[SelectProcedure("MNGKARGO.PCK_TEST.PRC_GET_ALL_TEST", "refcursor P_TEST:", DefaultSelect = true ) ] [SelectProcedure("MNGKARGO.PCK_TEST.PRC_GET_TEST_BY_ID","ID1",DefaultSelect=false)]

[InsertProcedure("MNGKARGO.PCK_TEST.PRC_INSERT_TEST", "NAME1", "VALUE1", "out P_ID1 : Int32 id1")]

[UpdateProcedure("MNGKARGO.PCK_TEST.PRC_UPDATE_TEST", "NAME1","VALUE1","ID1")]

[DeleteProcedure("MNGKARGO.PCK_TEST.PRC_DELETE_TEST","ID1")]

partial class TEST1DataTable

{

}


Neden birden çok Select Procedure var?  DataAdapter nesnesi her bir kayıtın RowState özelliğine göre kendisine ait InsertCommand, UpdateCommand, DeleteCommand fonksiyonlarında biri kullanılarak veriyi güncelleyecektir. Bu sebebten dolayı sadece birer tane Insert, Update ve Delete Store Procedure eklenmesine izin verilmiştir. Birden cok SelectCommand gerekecektir.

      Böylece artık Typed DataTable nesneleri Oracle Packet üzerinde ilişkili oldukları Store Procedure'leri bilmektedir. DataTable nesneleri için artık bir Generic DataAdapter nesnesileri oluşturabiliriz. Veri şemasını biliyoruz, veriyi veri tabanında işleyecek Store Procedure'leri biliyoruz o halde Data Access Layer üzerinde sürekli aynı kodları yazmanın gereği var mıdır? En tepeye Generic bir Data Access Layer yazar ve tüm Logic içerisinde bu sınıfı kullanırız. (İp ucu: Yerinizde olsam Base Logic sınıflarınıda Generic yapardım. Bu sayede bütünleşik ve tamamen Generic bir çatınız olur. Projelerinizi minumum kodlama ile bitebilirsiniz. Ben yaptım oldu :) )  

      IDataService ile tüm veri tabanı etkileşim ihtiyaçları ortaya konmuştur.

      Bu işlemleri gerçekleştiren OracleDataService sınıfıdır ki kendisi projede tek başına Data Access Layer olmaktadır. OracleDataService sınıfı kendisine tip parametresi olarak verilen Typed DataTable nesnesinin StoreProcedure Attribute'lerini almakta ve Odp.Net ile gelen OracleDataAdapter nesnesini bu Attribute'lere göre oluşturmaktadır.

StoreProcedureAttribute[] sps = (StoreProcedureAttribute[])table.GetType().GetCustomAttributes(typeof(StoreProcedureAttribute), false);

foreach (StoreProcedureAttribute att in sps)

{

if (att is InsertProcedure)

InitInsertProcedure(att.ProcedureName, att.Paramters);

else if (att is UpdateProcedure)

InitUpdateProcedure(att.ProcedureName, att.Paramters);

else if (att is DeleteProcedure)

InitDeleteProcedure(att.ProcedureName, att.Paramters);

else if (att is SelectProcedure)

InitSelectProcedure(att.ProcedureName, att.Paramters,(att as SelectProcedure).DefaultSelect );

else

InitCustomProcedure(att.ProcedureName, att.Paramters);

}

Odp.Net OracleDataAdapter nesnesine ait Commandları oluştur:

private Oracle.DataAccess.Client.OracleCommand InitStoreProcedure(string procedureName, string[] parameters)

{

Oracle.DataAccess.Client.OracleCommand command = new Oracle.DataAccess.Client.OracleCommand();

command.Connection = _connection;

command.CommandType = System.Data.CommandType.StoredProcedure;

command.CommandText = procedureName;

foreach (string parameter in parameters)

{

command.Parameters.Add(InitParameter(parameter));

}

return command;

}

Kullanımı gayet basittir:

Demo.Framework.Generic.Data.OracleDataService<DataSet1.TEST1DataTable, DataSet1.TEST1Row>

_dataAccessLayer = new Demo.Framework.Generic.Data.OracleDataService<DataSet1.TEST1DataTable, DataSet1.TEST1Row>();

public Form1()

{

InitializeComponent();

_dataAccessLayer.FillAll(dataSet1.TEST1);

}


private void tEST1BindingNavigatorSaveItem_Click(object sender, EventArgs e)

{

_dataAccessLayer.UpdateTable(dataSet1.TEST1);

}



 

       Değişken parametrele Store Procedure çağrılarını gene OracleDataService sınıfını kullanarak yapabilirsiniz.

       Sonuç: Tüm Data Access çağrıları sürekli aynı kodların tekrarı olmaktadır. Genelde manüel kodlama ile veya Code Genetor yazmak ile  bu sıkıcı kod bloğu oluşturulmaktadır. Yukarıda ki yaklaşım ile tekrar edilen kodlardan kurtulmuş olduk. Oracle ve Typed Dataset kullanan uygulamalar için genel (ve tecrübe ile sabit yeterli) bir Data Access Layer yazmış olduk. Aynı yaklaşımı SQL üzerinde de kullanabilirsiniz hatta sadece isim uzayını ve bir iki satır kodu değiştirerek aynı sınıfı kullanabilirsiniz. Fakat ben bunun yerine SQL ortamında size doğrudan XSD dosyalarını kullanmanızı öneririm.

 http://emrecoskun.blogspot.com/

28.03.2007

Emre Coşkun