Makale Özeti

Bu makalemizde MVC Framework 'te LinQ to SQL yardımı ile veri tabanı işlemlerini incelemeye çalışıyoruz.

Makale

Bir önceki makalemizde MVC Framework ‘ün ne işe yaradığını, nasıl bir mimari düşünce içersinde çalıştığını ve bu mimarinin bize katkılarının neler olduğuna değinmeye çalıştık. Sonrasında ise ilk MVC uygulamamızı açarak bize hazır olarak oluşturulan klasörlerin sınıfların ve web servis kontrollerine göz atmaya çalıştık. Daha sonrasında ise View ve Controller içeriklerini kontrol ederek işlemlerimizi tamamlamış olduk.

View ve Controller kavramlarını inceledik fakat bir diğer katman olan Modele yalnızca isim olarak değindik ve ne işe yaradığından bahsetmiştik. Bu makalemizde ise MVC Framework ‘te veri tabanı işlemlerimizi yapmamıza yarayacak olan Model katmanını incelemeye çalışacağız.

Model katmanını incelerken LinQ to SQL ile sorgularımızı daha nesnesel bir şekilde kullanırken veri tabanı olarak da SQL SERVER 2005 ile birlikte gelen örnek veri tabanlarından Adventure Work 'u kullanacağız.



Yazımızın ayrıntılarına girmeden önce isterseniz tekrardan Modelin ne olduğunu hatırlayalım.

Model: Model genellikle veri tabanı işlemlerimizi yani işlerimizi( business ) yaptığımız yapıdır. Veri tabanımız üzerinde yapılabilecek sorgularımızı burada belirler ve Controller ’ı atamamızı sağlarız. Bu sayede veri tabanımıza dışarıdan daha kolay erişebilir ve çeşitli metotlarla daha kolay idare/müdahale edilebilir hale getirir.

Şimdi model katmanını incelemeye başlayabiliriz. Model veri tabanı işlemlerinin yapıldığı bir katman olduğundan ötürü bizde bunu örnek üzerinden anlatmaya çalışacağız.

Uygulamamıza başlarken File-->New-->Project adımlarını izleyerek ASP.NET MVC Web Application seçeneğini seçiyoruz. Projemizin ismini de AdventureWorkMerhaba olarak belirledikten sonra projeyi tamam butonuna basarak uygulamamızı oluşturuyoruz.



Veri tabanımızı uygulamamıza ekleyebilmek için Server Explorer bölümünden Data Connections ‘ın üzerinde sağa tıklayarak Add Connection seçeneğini tıklarız.



Karşımıza Server adını ve veri tabanı ismini girmemizi isteyen bir ekran gelecektir. Bu bölümde de server ismini (eğer SQLExpress kullanıyorsanız server ismi = sqlexpress ‘tir) girdikten sonra database isminin olduğu bölümün içeriği otomatik olarak bizim üzerinde çalışmakta olduğumuz veri tabanları ile doldurulur. Bizde oradan AdventureWork ‘ü seçerek tamam dediğimizde artık uygulamamızın bir veri tabanı oluyor.



Uygulamamızda kullanacak olduğumuz veri tabanına ait sorgularımızı model katmanının içerisinde oluşturacağımızdan ve bu sorguları da LinQ to SQL yardımı ile yapacağımızdan bahsetmiştik. Bu sebepten ötürü Model klasörümüzün içerisine gerekli olan sınıfı eklememiz için model klasörünün üzerine sağa tıklayarak Add-->NewItem basamaklarını uygulaya biliriz.



Yeni öğe ekleme seçeneğinin içeriği açıldığı zaman karşımıza her zamankinden farklı öğeler karşılamaktadır. Karşılaşılan öğeler MVC ile ilgili olanlardır. Bunların listede yer almasının başlıca sebebi MVC Framework ‘ü kurmamızdır. Eğer bu Framework ‘ü kurmadan MVC uygulaması yapmaya çalışsaydık daha önceki zamanlarda olduğu gibi bu öğelerin hazırlanması içinde uzunca bir zaman ayırmamız gerekecekti.



Bu öğeleri bir kenara bırakırsak bizim işimize yarayacak olan sınıfı eklemek için karşımızda listeden LinQ to SQL Classes ‘ı bularak ismini AdventureWork olarak belirledikten sonra tamamı seçerek uygulamamıza ekliyoruz.



Eklediğimiz zaman dikkatimizi çeken birkaç nokta oluyor. Bunlardan birinci referanslar bölümünde yeni eklenen referansların olması. Bu referanslar LinQ to SQL ile ilgili sınıfları ve özellikleri kullanmamız için gereklidir.



İkincisi ve en önemlisi olanda *.dbml uzantılı bir dosya oluşturuyor. DBML database Markup Language anlamına gelen ve yardımcı veri olarak kullanılmakta olan bir sınıftır.

AdventureWork.dbml ‘imizi oluşturduğumuzda bizden uygulamamızdaki veri tabanına ilişkin tabloları eklememizi beklemeye başlayacaktır. Şimdi de bu işlemleri nasıl yapacağımıza değinmeye çalışalım.

Daha önceden eklemiş olduğumuz veri tabanının tablolarından ihtiyacımız olanları Object Relationel Designer (ORD) yazan yere sürükleyip bırakıyoruz. Biz bu uygulama için tablolardan Product, ProductOrderDetail ve ProductCategory ‘i ORD ‘ye sürükleyerek tabloların ve bu tablolara ait özelliklerin ekran gözükmesini sağlamış oluruz. Ayrıca bu tablolar arasında herhangi bir ilişki var ise onlarda otomatik olarak ekranda oluşturulacaktır.


İlişkileri oluşmuş olan tablolarımızı kaydedip kapattıktan sonra dmbl dosyamızın arka planında oluşan kodlarına göz atalım. Bakalım veri tabanı tablolarımız ve bu tablolarımıza ilişkin özellikler nasıl oluşmuş.

Oluşmuş olan kodları aşağıdaki tablonun içersinde bulabilirsiniz. Fakat verecek olduğumuz kod bloğu oluşturulmuş olan kodun tümü değildir. Bunun sebebi ise yaklaşık 1250 satır kodun oluşturulmasıdır.

Kodları vermeden önce daha önceden asp.net, Java veya başka bir dille oluşturmuş olduğumuz model sınıflarında tek tek tablolarda yer alan özellikleri tanıtmak zorunda kalır ve bu özelliklere ilişkin verilen/alınan değerlerini de ayrıca elimiz yardımı ile girmek zorunda kalırdık. Bu işlem esnasında birçok sorunla da karşılaşmamız mümkündü. Biraz önce uygulamış olduğumuz yöntem sayesinde bize zaman kaybettiren birçok kodu yazmaktan kurtulabiliriz. Fakat aklınıza güvenli mi veya doğru mu oluşturuldu biçiminde sorular takılabilir. Bunun cevabı eper ekstra işlem yapmayacaksak doğru ve güvenilirdir. Fakat tablolar arası join gibi işlemler yapmak istersek tabii ki de otomatik olarak oluşturulan kodu düzenlememiz gerekecektir.

Join işlemlerini neden örnek verdiğimize gelirse. SQL de join işlemleri birçok tablodan alınan değerler sonucunda bize sonuçlar döndürebilmekteydi. Bu tür işlemleri sql kodları ile yapmak kolaydı. Çünkü herhangi bir sınıftan veya başka bir yerden özellik çağırmadan sql kodları ile işlemlerimizi yapabiliyorduk. Fakat Model katmanında tabloları ayrı ayrı parçalı sınıflar biçiminde tuttuğumuz için ve benzer isimli sütunlarda oluşabileceği için sorgulama işlemlerimizde sorunlar çıkabilmekteydi. Bu sorunların kaldırılması içinde model katmanda oluşturmuş olduğumuz sınıflara o kullanacak olduğumuz sütunlara ilişkin özellikleri tanımlamalı ve işlemlerimize öyle devam etmeliydik. İşte bizimde şu anda oluşturmuş olduğumuz dbml ‘in arka planındaki kodlar en basit biçimiyle oluşturulmaktadır. Bizler onu özelleştirmek istersek buna imkan tanınmıştır.

C#
[System.Data.Linq.Mapping.DatabaseAttribute(Name="AdventureWorks")]
public partial class AdventureWorkDataContext : System.Data.Linq.DataContext
{

   private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();

#region Extensibility Method Definitions
//SQL ile yapılabilecek işlemler otomatik olarak tanımlandı
partial void OnCreated();
partial void InsertProduct(Product instance);
partial void UpdateProduct(Product instance);
partial void DeleteProduct(Product instance);
partial void InsertPurchaseOrderDetail(PurchaseOrderDetail instance);
partial void UpdatePurchaseOrderDetail(PurchaseOrderDetail instance);
partial void DeletePurchaseOrderDetail(PurchaseOrderDetail instance);
partial void InsertProductCategory(ProductCategory instance);
partial void UpdateProductCategory(ProductCategory instance);
partial void DeleteProductCategory(ProductCategory instance);
#endregion

-----------------------
//Product tablosuna ait parçalı sınıfa bakarsak
-----------------------

//Product tablosuna ilişkin özellikler ve değerleri
[Table(Name="Production.Product")]
public partial class Product : INotifyPropertyChanging, INotifyPropertyChanged
{

   private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

   private int _ProductID;
   private string _Name;
   private string _ProductNumber;
   private bool _MakeFlag;
   private bool _FinishedGoodsFlag;
   private string _Color;
   private short _SafetyStockLevel;
   private short _ReorderPoint;
   private decimal _StandardCost;
   private decimal _ListPrice;
   private string _Size;
   private string _SizeUnitMeasureCode;
   private string _WeightUnitMeasureCode;
   private System.Nullable<decimal> _Weight;
   private int _DaysToManufacture;
   private string _ProductLine;
   private string _Class;
   private string _Style;
   private System.Nullable<int> _ProductSubcategoryID;
   private System.Nullable<int> _ProductModelID;
   private System.DateTime _SellStartDate;
   private System.Nullable<System.DateTime> _SellEndDate;
   private System.Nullable<System.DateTime> _DiscontinuedDate;
   private System.Guid _rowguid;
   private System.DateTime _ModifiedDate;
   private EntitySet<PurchaseOrderDetail> _PurchaseOrderDetails;
#region Extensibility Method Definitions

//Listenin bir kısmıdır. Aslında birçok metot bulunmaktadır.
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnProductIDChanging(int value);
partial void OnProductIDChanged();
partial void OnStandardCostChanged();
partial void OnListPriceChanging(decimal value);
partial void OnListPriceChanged();
partial void OnSizeChanging(string value);
#endregion

public Product()
{
   this._PurchaseOrderDetails = new EntitySet<PurchaseOrderDetail>(new Action<PurchaseOrderDetail>(this.attach_PurchaseOrderDetails)      , new Action<PurchaseOrderDetail>(this.detach_PurchaseOrderDetails));
      OnCreated();
}

[Column(Storage="_ProductID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int ProductID
{
   get
   {
      return this._ProductID;
   }
   set
   {
      if ((this._ProductID != value))
      {
         this.OnProductIDChanging(value);
         this.SendPropertyChanging();
         this._ProductID = value;
         this.SendPropertyChanged("ProductID");
         this.OnProductIDChanged();
      }
   }
}

[Column(Storage="_Name", DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
public string Name
{
   get
   {
      return this._Name;
   }
   set
   {
      if ((this._Name != value))
      {
         this.OnNameChanging(value);
         this.SendPropertyChanging();
         this._Name = value;
         this.SendPropertyChanged("Name");
         this.OnNameChanged();
      }
   }
}

//Özelliklere ilişkin metotlar devam etmektedir...

dbml ‘in kod bloğu yukarda ki gibidir. Bu kod bloğunda yalnızca Product tablosu değil diğer eklemiş olduğumuz tablolarda bulunmaktadır.

Şimdi yapmamız gereken model içerisine eklemiş olduğumuz tablolara ilişkin verileri Controller üzerinden çağırarak kullanmaktır. Bu işlemi yapabilmemiz için bir parçalı sınıf oluşturmalı ve oluşturmuş olduğumuz bu sınıfı ControllerAction yardımı ile çağırılabilir bir biçime dönüştürmeliyizdir. Ayrıca oluşturmuş olduğumuz parçalı sınıfın içersinde de yapacağımız işlemleri list içerisinde belirlememiz gerekmektedir.

Sınıfımızı oluşturmaya başladığımızda uygulamamızda oluşturulmuş olan isim alanlarına ulaşmak istediğimizde uygulamaismi. dememiz yeterli olacaktır.



Karşımıza çıkan isim alanları listesinden Models ‘ı seçtikten sonra karşımıza dört farklı seçebileceğimiz sınıf çıkacaktır. Bunlardan üçü bizim eklediğimiz tabloları temsil etmektedir. Dördüncüsü ile veri içeriğini temsil etmektedir. Bu veri içeriği dbml dosyamızda oluşturulmuş olan sınıfın içerisinden bir tiptir. İçeriğe erişmek için kullanmakta yarar vardır.



Veri içeriğini tanımladıktan sonra ayrıntılarını görmek istediğimizde, tabloları LinQ içerisinde belirlenmiş olduğunu görürüz.



Daha sonra yapacağımız işlem ise çağıracak olduğumuz tablonun görülebilmesi için RenderView üyesinin içerisinde tanımlayarak Controller ‘a istek geldiğinde anlayabilmesine olanak tanımaktadır. Bu isteği algılayabilmesi de alınan değer ve değere ilişkin tablo biçimin kod bloğunda yazılması gerekmektedir.



Hazırlıklarımızı tamamladığımıza göre normal olarak uygulamamızı çalıştırdığımızda sorunsuz bir biçimde derlenmesi ve işlemesi gerekmektedir.

Uygulamamız sorunsuz bir biçimde derlendi ve web sayfamız karşımıza geldi. Şimdi ise bizden istek yapmamızı beklemektedir. Normal zamanlarda form üzeriden sayfaya istek yaptığımızda View ‘ın içerisinde olan sayfaları çağırmaya çalışacaktır.

Bizde oluşturmuş olduğumuz list öğesini çağırmak için tarayıcımızın adres çubuğunu http://localhost:49170/Home/List yazıyoruz. Bu yazdığımız adrese göre tarayıcımız isteğini yapacak ve Controller da bu istek doğrultusunda gerekli olan sayfayı çağıracaktır.

Fakat her şey düşündüğümüz gibi olmuyor ve aşağıdaki hatayı alıyoruz.



Karşılaştığımız hataya dikkat ettiyseniz Products.aspx sayfası bulunamadı diyor. Fakat bu Products.aspx ‘i neden arıyor? Biz internet tarayıcımızın adres çubuğuna home/List ‘i çağırmasını istemiştik. Bunun sebebi Controller içerisinde hazırlamış olduğumuz list member ‘inin içerisinde eğer kullanıcıdan böyle bir istek gelirse adı Product olan sayfaya yönlendirmesini istemiştik. O da görevini yaparak View/Home klasörünün altında Products.aspx ‘i aramaktadır. Fakat biz öyle bir sayfa eklemediğimiz için bulamamaktadır.

O zaman bizde Products.aspx sayfasını ekleyelim ve sonucun nasıl olacağını görmeye çalışalım. Bu işlemi yapabilmemiz için View/Home klasörünün üzerinde Add/NewItem diyerek karşımıza ekleyebileceklerimizin listesini çıkartıyoruz. Bu listeden standart aspx sayfasını seçmek yerine MVC ‘den türetilecek olan MVCViewPage ‘i seçmek bizim işimizi kolaylaştıracaktır.



Sayfamızı ekledikten sonra içeriğine rastgele bir şeyler yazarak derlediğimiz zaman adres çubuğunda Home/List şeklinde bir çağırma olduğu dikkatimizden kaçmamaktadır.

Şimdi ise web sayfamızın içerisinden modelde tanımlanmış olanların hangilerine ve nasıl erişeceğimize göz atalım.

Temel asp bilgimizden <% %> bloklarının arasına kod yazılabildiğini biliyoruz. Şimdi web sayfamızda bu blokları kullanarak verileri göstertmeyi deneyelim. Bunun için yazmamız kod ViewData ‘dır. Bu kodu kullanmamız sonrasında intellisense ile karşımıza gelen sınıfların arasında veri içeriğinin de olduğunu görürüz.



Şimdi ViewData ‘dan sonra alacağımız özellikleri, sınıfları v.b. diğer bir çok şeyi Product ‘ın içerisinden almak istiyoruz. Bunu yapmak için, web sayfamızın kod tarafında hazır olarak oluşturulmuş sınıfa generics (genel) tanımlayarak Product ‘taki bütün verileri almasını sağlayabiliriz. Bunu yapabilmek için aşağıdaki gibi bir kod oluşturmamız gerekmektedir.

Alınabilecek değerler,



Bu görünebilir veri değerine Product yazıpta uygulamamızı derledikten sonra web sayfamızın içeriğinden olan ViewData ‘nın intellisence ile bize getirecekleri aşağıdaki gibi olacaktır.



ViewData ‘nın içerisinde karşımıza çıkan bu properties ‘lerin içeriklerini görmek istersek yapmamız gereken işlem kod tarafında tanımlamış olduğumuz Product ‘ı IEnumerable ‘ın içeriğinde tanımlamak olacaktır.



Bu değişikliğin sonucunda ViewData ile intellisense kullandığımızda karşımıza extensionlar aşağıdaki gibidir.



Yapacağımız sıradaki işlem ise Product tablosunun altında yer alan ProductName ‘leri ekrana basmak olacaktır. Bunu yapabilmek için foreach kullanmamız yeterli olacaktır.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Products.aspx.cs" Inherits="AdventureWorkMerhaba.Views.Home.Products" %>
<%@ Import Namespace="AdventureWorkMerhaba.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
 <head runat="server">
  <title></title>
 </head>
   <body>
      <div>
         hede... bu bir deneme sayfasidir
         <ul>
         <% foreach (Product p in ViewData)
            {

         %>
         <li><%=p.Name%></li>

         <%   } %>
         </ul>
      </div>
   </body>
</html>

Sayfamızı derlediğimiz zaman aldığımız sonuç oldukça iyidir. Bütün liste karşımızdadır.



Fakat bütün liste karşımızda olmasına rağmen masterpage ‘in tasarımını almamıştır. Ona erişebilmek için ise index.aspx ‘in içerisinde yer alan MasterPageContainer ‘larını Product.aspx ‘e ekleyerek tasarımı kazanmasını sağlayabiliriz.

Master page ‘imizi ekledikten sonra ise karşılaştığımız listenin daha şirin ve düzenli gözükebilmesi için css ‘imizin içerisinde yeni bir tasarım oluşturalım. Oluşturacak olduğumuz tasarım aşağıdaki gibi olacaktır.



Bu hazırladığımız tasarım sonucunda ise derleme esnasında web sayfamız aşağıdaki gibi bir görünüme kavuşacaktır.



Bu makalemizde MVC Framework ‘ü ve LinQ to SQL ’i kullanarak verilere erişimi ve sayfada göstermeyi anlatmaya çalıştık. Bir sonraki makalemizde ise ID ‘ler aldığımız değerleri kullanarak güncelleme yapmayı ve silmeyi incelemeye çalışacağız.

Umarım yararlı olmuştur.

Uygulamanın kaynak kodlarına download bölümünden erişebilirsiniz. Veri tabanı dosyası kaynak kodlarda değildir. SQL server örnek veritabanından erişebilmeniz mümkündür. Sizin örneği çalıştırabilmeniz için WebConfig dosyasında gerekli düzenlemeleri yapmanız gerekmektedir.

Turhal Temizer
http://turhal.blogspot.com
Uygulamanın kaynak kodları