Sqlde başka bir serverdaki procedure'u vs. openquery ile çağırırken şu hatayı alırsak;
The OLE DB provider "SQLNCLI10" for linked server "LinkedServer" supplied inconsistent metadata for a column. The name was changed at execution time.
yapmamız gereken, openquery ile çalıştırdığımız procedure sorgusuna SET FMTONLY OFF sorgusunu eklemek olmalı. Sonuç olarak, procedure'u execute ederken;
SELECT * FROM OPENQUERY('LinkedServer','SET FMTONLY OFF EXEC Procedureİsmi')
25 Ocak 2012 Çarşamba
24 Ocak 2012 Salı
"Logon failure unknown username or bad password" hatası ve çözümü
Geçen gün bir uygulama geliştirirken şöyle bir ihtiyacım oldu. İstenilen paylaşıma açık bir dosyanın içine xml formatında bir klasör oluşturup kaydeden bir web servis yazmam istendi. Tüm kodlamaları yaptım, localde doğru çalışan uygulamayı servera attığımda, tam xml'in save edildiği noktada program catch'e düştü ve şu hata mesajını verdi.
"logon failure unknown username or bad password"
Önce klasörü tüm kullanıcılara yetki verecek şekilde ayarladım, ardından IIS User ekledim fakat hiçbiri işe yaramadı. Küçük araştırma sonucu şöyle bir çözüm buldum.
WebConfig'in içinde system.web tagının altına şu satırı yerleştirdiğimiz zaman sorun çözülmüş olacak.
"logon failure unknown username or bad password"
Önce klasörü tüm kullanıcılara yetki verecek şekilde ayarladım, ardından IIS User ekledim fakat hiçbiri işe yaramadı. Küçük araştırma sonucu şöyle bir çözüm buldum.
WebConfig'in içinde
<identity impersonate="true" userName="domain\username" password="password" />
30 Ekim 2011 Pazar
23 Ekim 2011 Pazar
Sql'de Recompile
Sql'de Stored Procedure yazarken arka planda üç temel iş gerçekleşir. Bunlar Parsing,Compiling ve Executing'dir. Kısaca neler olduklarını açıklamak gerekirse,
Parsing, yazdığımız kodun syntax olarak hata içerip içermediğinin kontrol zamanıdır,
Compiling, yazdığımız prosedürün execution planını oluşturup bunu geçici hafızaya atılma zamanıdır,
Executing ise anlaşılacağı üzere kodun çalıştığı anda DML'e bildirilen zamandır.
İşte compiling zamanında execution plan'ın hafızaya atılması bazı durumlarda kodumuza hız katabilir. Fakat bazı durumlarda da tablo yapıları veya indeksler çok sık değiştiğinden bu hafızaya atılan execution plan'lar yarar yerine zarar getirir. Bunu nasıl anlarız? ilk derlemede prosedürümüz hızlı çalışıp, sonraki çalıştırmalarda gözle görülür bir yavaşlama varsa, nedeni bu olabilir. Bundan kaçınmak için yapmamız gereken RECOMPILE keyword'unu prosedüre tanıtmak. Kısaca kullanılışı;
Böylece Recompile yazarak, artık execution plan'ın hafızaya atılmasını engelledik.
Parsing, yazdığımız kodun syntax olarak hata içerip içermediğinin kontrol zamanıdır,
Compiling, yazdığımız prosedürün execution planını oluşturup bunu geçici hafızaya atılma zamanıdır,
Executing ise anlaşılacağı üzere kodun çalıştığı anda DML'e bildirilen zamandır.
İşte compiling zamanında execution plan'ın hafızaya atılması bazı durumlarda kodumuza hız katabilir. Fakat bazı durumlarda da tablo yapıları veya indeksler çok sık değiştiğinden bu hafızaya atılan execution plan'lar yarar yerine zarar getirir. Bunu nasıl anlarız? ilk derlemede prosedürümüz hızlı çalışıp, sonraki çalıştırmalarda gözle görülür bir yavaşlama varsa, nedeni bu olabilir. Bundan kaçınmak için yapmamız gereken RECOMPILE keyword'unu prosedüre tanıtmak. Kısaca kullanılışı;
CREATE PROCEDURE SatisRapor
WITH RECOMPILE
AS
....Böylece Recompile yazarak, artık execution plan'ın hafızaya atılmasını engelledik.
30 Temmuz 2011 Cumartesi
Tek Satırda If Komutu
If-Else yapılarının tek satırda toplanmış hali;
sonuc = (sayi%2==1) ? "Tek":"Çift";
Yapısı kısaca,
(koşul ifadesi) ? "True" : "False";
20 Temmuz 2011 Çarşamba
C# Dosya Yazma-Okuma İşlemleri(Input-Output)
C#'da uygulama geliştirirken çokça kez bir dosyaya veri yazma, veya bir dosyadan veri okuma gibi ihtiyaçları hissederiz. Şimdi size, basit olarak en kısa yoldan, bir dosyadan veri okunmasını ve yazılmasını anlatacağım.
Öncelikle dosyadan veri okuma ve yazma işlemlerimizi yerine getiren 2 sınıfımız var. Veri okuma işlemleri için, StreamReader,veri yazma işlemleri için de StreamWriter classlarını kullanırız. Kısaca kodlar üzerinden anlamaya çalışalım.
1-Veri Okuma :
FileStream classının constructorında, sınıfa parametre olarak sırasıyla, dosyanın yolu,dosya belirtilen yolda bulduktan sonra hangi işlemi yapacak (burada açmasını istedik),üçüncü parametre olarak da bu dosyanın okunacağını belirtiyoruz. Ardından, verileri okumamızı sağlayan StreamReader sınıfına bu dosyamızı veriyoruz.
Ardından, senaryomuza göre dosyada satır satır bulunan id'leri ReadLine() metodu sayesinde okuyup, son satır gelene kadar aralarına virgül koyarak ayırıyoruz. En son satırda da virgül olacağından, o virgülü silmek için de substring metodunu kullanıyoruz. Böylece, örnek dosyamızda;
123
456
789
...
şeklinde olan veri;
123,456,789
şeklinde okunacak.
2- Veri Yazma :
Burada da, yine aynı şekilde, önce StreamWriter nesnemizi oluşturduk. Yalnız, burada dikkat etmemiz gereken nokta, StreamWriter'in string ve bool parametresini alan overload'ını kullanmamız gerekir. Aksi taktirde, veri okurkenki gibi 3 parametreli overload'ını kullanırsak, dosyamıza append edemeyiz verilerimizi. Yani verilerimiz sürekli üst üste yazılacağından, biri silinirken diğeri yazılacak, dolayısıyla sadece en son veri ekranda yazılmış olacak. Bu yöntemle, ikinci parametreye true vererek, append işlemi yapmak istediğimizi söylüyoruz ve TextBox'ımızın içinde yazan değeri de yazmış oluyoruz belirttiğimiz dosyaya.
Görüldüğü gibi, veri okuma ve veri yazma işlemleri oldukça kolay. Yapmamız gereken, FileStream nesnesini oluşturup, veri yazılacak veya okunacak dosyayı tanıtıp, hangi işlemleri yapmak istediğimizi belirtip, bizden istenen işleme göre (okuma-yazma) StreamReader veya StreamWriter classlarını kullanıp, gerekli metotlar sayesinde istediğimiz işlemleri yapmak olacaktır.
Öncelikle dosyadan veri okuma ve yazma işlemlerimizi yerine getiren 2 sınıfımız var. Veri okuma işlemleri için, StreamReader,veri yazma işlemleri için de StreamWriter classlarını kullanırız. Kısaca kodlar üzerinden anlamaya çalışalım.
1-Veri Okuma :
FileStream file = new FileStream(@"C:\\ergin2.txt", FileMode.Open, FileAccess.Read);
StreamReader read = new StreamReader(file);
FileStream classının constructorında, sınıfa parametre olarak sırasıyla, dosyanın yolu,dosya belirtilen yolda bulduktan sonra hangi işlemi yapacak (burada açmasını istedik),üçüncü parametre olarak da bu dosyanın okunacağını belirtiyoruz. Ardından, verileri okumamızı sağlayan StreamReader sınıfına bu dosyamızı veriyoruz.
string s = "";
string line = "";
while ((line = read.ReadLine()) != null)
{
s += line + ",";
}
if (s.Length > 1)
s = s.Substring(0, s.Length - 1);
Ardından, senaryomuza göre dosyada satır satır bulunan id'leri ReadLine() metodu sayesinde okuyup, son satır gelene kadar aralarına virgül koyarak ayırıyoruz. En son satırda da virgül olacağından, o virgülü silmek için de substring metodunu kullanıyoruz. Böylece, örnek dosyamızda;
123
456
789
...
şeklinde olan veri;
123,456,789
şeklinde okunacak.
2- Veri Yazma :
StreamWriter sw = new StreamWriter(@"C:\\ergin2.txt", true);
sw.WriteLine(txtId.Text);
Burada da, yine aynı şekilde, önce StreamWriter nesnemizi oluşturduk. Yalnız, burada dikkat etmemiz gereken nokta, StreamWriter'in string ve bool parametresini alan overload'ını kullanmamız gerekir. Aksi taktirde, veri okurkenki gibi 3 parametreli overload'ını kullanırsak, dosyamıza append edemeyiz verilerimizi. Yani verilerimiz sürekli üst üste yazılacağından, biri silinirken diğeri yazılacak, dolayısıyla sadece en son veri ekranda yazılmış olacak. Bu yöntemle, ikinci parametreye true vererek, append işlemi yapmak istediğimizi söylüyoruz ve TextBox'ımızın içinde yazan değeri de yazmış oluyoruz belirttiğimiz dosyaya.
Görüldüğü gibi, veri okuma ve veri yazma işlemleri oldukça kolay. Yapmamız gereken, FileStream nesnesini oluşturup, veri yazılacak veya okunacak dosyayı tanıtıp, hangi işlemleri yapmak istediğimizi belirtip, bizden istenen işleme göre (okuma-yazma) StreamReader veya StreamWriter classlarını kullanıp, gerekli metotlar sayesinde istediğimiz işlemleri yapmak olacaktır.
Etiketler:
C#,
Dosya Okuma Yazma İşlemleri,
U_Input Output
16 Temmuz 2011 Cumartesi
Asp.Net'de Sayfa İçi Tema Değiştirme
Sitemizde, sayfanın görselliğini kullanıcıya bırakmak için, tema değişikliği vs. gibi işlemler, son derece profesyonel ve göze hoş gelir. Şimdi, asp.net sayfalarında tema değişikliği nasıl yapılır bunu kısaca anlatmaya çalışacağım.
Öcelikle projemize sağ tıklayıp, add asp.net folder ve Theme diyip temamızı oluşturuyoruz. Temamızın içine css dosyası da ekledikten sonra basit olarak css'in içine arka plan rengi ve yazı rengi verelim. Örneğin bir mavi, bir de kırmızı temamız olsun. Bunun için şöyle bir css kodu yazalım,
Kırmızı Tema
Şimdi de bu tema değişikliğini kullanıcıya bırakalım. Yani kullanıcı isterse Mavi, isterse kırmızı temayı kendi seçip kullansın. Bunun için bir dropdownlist koyup, kullanıcının seçimine göre değişikliği yapalım.
Öncelikle ilk akla gelen, dropdownlist'in autopostback özelliğini true yapıp, selectedindexchanged eventi tetiklendiğinde tema değişikliğini yapmak. Fakat bu işlemi yaptığımızda göreceğiz ki, uygulama şöyle bir exception fırlatacak;
The 'Theme' property can only be set in or before the 'Page_PreInit' event.
Bunun anlamı, LifeCycle süreci bazı sırayla gerçekleşir. Sayfa oluşurken,
Bu kodu yazdığımızda da şöyle bir sorun çıkar. Asp.Net kontrolleri Load eventinden önce oluşur fakat markuptaki halleriyle oluşur. Yani boş bir şekilde sadece DropDownList'in oluştuğunu görürüz. Load metodunda içi dolar. Dolayısıyla PreInit, Load'dan önce çalıştığından hata verecektir. Peki Load eventinden önce kontrollerin değerlerine nasıl erişiriz.
Öcelikle projemize sağ tıklayıp, add asp.net folder ve Theme diyip temamızı oluşturuyoruz. Temamızın içine css dosyası da ekledikten sonra basit olarak css'in içine arka plan rengi ve yazı rengi verelim. Örneğin bir mavi, bir de kırmızı temamız olsun. Bunun için şöyle bir css kodu yazalım,
Kırmızı Tema
body
{
background-color:Red;
color:White;
}
Mavi Tema
body
{
background-color:Blue;
color:White;
}
- Constructor
- PreInit
- Init
- Load
- PreRender
- UnLoad
metotları sırasıyla çalışır ve sayfa oluşur. Dolayısıyla, tema atama, setleme işlemleri de PreInit'de gerçekleştiğinden burada da PreInit metodumuzu yazıp, Temayı setleyelim.
protected void Page_PreInit(object sender, EventArgs e)
{
Theme = DropDownList1.SelectedValue;
}
Bu kodu yazdığımızda da şöyle bir sorun çıkar. Asp.Net kontrolleri Load eventinden önce oluşur fakat markuptaki halleriyle oluşur. Yani boş bir şekilde sadece DropDownList'in oluştuğunu görürüz. Load metodunda içi dolar. Dolayısıyla PreInit, Load'dan önce çalıştığından hata verecektir. Peki Load eventinden önce kontrollerin değerlerine nasıl erişiriz.
Cevap, Request nesnesi sayesinde. Aslında Load'da da Request ile erişebiliriz fakat, Visual Studio uzun uzun yazmayalım diye, öyle bir kolaylık sağlamış bize DropDownList oluştuğu için. Dolayısıyla PreInit'den seçilen değeri alabilmemiz için şu kodu yazmalıyız;
protected void Page_PreInit(object sender, EventArgs e)
{
if(Request.RequestType == "POST")
{
Theme = Request.Form["DropDownList1"];
}
}
kodu RequestType'ını kontrol etmemizin amacı, get taleplerinde var olan temayı default olarak vermek. Yani sayfa ilk açıldığında boş bir template ile açılsın, daha sonra dropdownlist post edildiğinde içindeki değer PreInit metodunda okunsun ve temamız değişsin. Ekran çıktısına baktığımızda ise şöyle bir sonuç görürüz;
Substition Cache Kavramı
Substition Cache kısaca, sayfanın tümünün cachelenip, sadece bazı bölümünün dinamik olarak değiştiği sayfalarda kullanılır. Örneğin, sayfanız 2-3 ayda bir yenileniyordur fakat, sayfanın en altında merkez bankasından o anki kuru alıyorsunuzdur. Çok ufak bir bölüm için, sürekli tüm sayfayı yeniden oluşturup, html render etmeye gerek yok. Bunun yerine tüm sayfayı cacheleyip, sadece o kısmı hariç tutarsak, daha doğru bir kodlama yapmış oluruz. İşte bu tür cacheleme biçimine de Substititon Caching denir.
Substition caching yapmak için, önce tüm sayfayı output cache'e koymamız gerekir. Bunun için sayfamıza,
Bu metot ismini de Substition kontrolünün property'lerinde bulunan MethodName özelliğine verirsek, artık sayfamız istediğimiz biçimde, sadece belli bölgesi dinamik olacak şekilde cachelenmiş olarak çalışacak. Ekran çıktılarına bakacak olursak;
Substition caching yapmak için, önce tüm sayfayı output cache'e koymamız gerekir. Bunun için sayfamıza,
<%@ OutputCache VaryByParam="none" Duration="300" %>
ekleriz. Böylece, şu anda tüm sayfamızı cachelemiş olduk. Şimdi sayfamızda dinamik gelmesini istediğimiz kısmı oluşturmamız gerekecek. Bunun için ToolBox'da bu işlem için Substition kontrolünün olduğunu görüyoruz. Bu kontrolün görevi, bulunduğu kısıma (bu kısım div, td ..vs gibi bir yer olabilir) dinamiklik getirmek.
2x2'lik bir table oluşturup, kolonlardan birine label ve Substition kontrolünü atıp, sayfanın PageLoad'ına o label'ın text'ine o anki saati yazdıralım. Tabiki tüm sayfa cacheli olduğundan bir de sayfada herhangi bir yere label koyup, o label'a da o anki saati yazdıralım. Bu işlemleri yapıp çalıştırdığımızda göreceğiz ki, sayfada bulunan label, bir kere o anki saati gösterip, 300 sn boyunca sürekli aynı saati cacheden getirecek. Fakat td'nin içinde bulunan saat, sürekli olarak dinamik olarak saati getirecek.
Sayfanın bu şekilde oluşmasını bekleriz. Akıllara şöyle bir soru gelebilir. Sayfa cache'den geldiğinden, page lifecycle süreci çalışmayacak, dolayısıyla html render edilip bize geri dönmeyecek. Çünkü ilk get talebimizde bu işlemler yapılıp cache'e atılmıştı. Peki, substition kontrolü ile gerçekleştirdiğimiz dinamik yapı da, lifecycle sürecine katılmayıp html olarak bize geri gelmeyecek mi?
İşte bu sıkıntıdan kurtulmak için, Substition kontrolü bizden bir metot yazmamızı istiyor. Bu metot, cache'den gelen, daha önce render edilmiş html'in içine gömüleceğinden, geriye string döndürmeli. Dolayısıyla biz geriye, html formatında bir yapı döndürmeliyiz. Çünkü lifecycle sürecini hatırlarsak, sayfaya talep yaptığımız zaman, compiler html oluşturup bize geri gönderiyor ve sayfamız ortaya çıkıyor. Burada da, dinamikliği oluşturduğumuz kısım da html'in içinde yer alması gerektiğinden, bizim bu metotda html formatında bir string geri döndürmemiz gerekir. Ayrıca, şunu da unutmamalıyız ki, sayfa cache'den geleceğinden, sayfa oluşmadan bu metot çalışacak. Dolayısıyla metodumuzu static yapmalıyız. Bu durumda metotumuzu yazarsak, basit olarak;
protected static string DinamikIcerik()
{
return string.Format("<İnput type='text' value='{0}' />", DateTime.Now.ToLongTimeString());
}
Bu metot ismini de Substition kontrolünün property'lerinde bulunan MethodName özelliğine verirsek, artık sayfamız istediğimiz biçimde, sadece belli bölgesi dinamik olacak şekilde cachelenmiş olarak çalışacak. Ekran çıktılarına bakacak olursak;
NOT: Üstteki Labellarda gösterilen saatler, sayfa içerisinde cache'den getirilen saatlerken, altta bulunan saat ise td'nin içinde bulunan substition kontrolü sayesinde dinamik olarak gelen saattir.
NOT2: Yukarıda, yazdığım metotda bulunan span html kontrolünde, blogger editörü html kodlarını derlediğinden bilerek ve isteyerek büyük i -İ- harfini koydum, blogun derleyememesi için. Heyecan yapmayınız.
Http Requestlerinin Dinlenmesi (Page sınıfından kalıtılmayan sınıflarda)
HTTP requestlerini dinleyebildiğimiz ve onlarla ilgili işlemler yapabildiğimiz bazı metotlar, property'ler, kısaca bazı üyeler vardır. Örnek vermek gerekirse, Server.MapPath ile uygulamanın, bulunduğu serverdaki çalıştığı dosyanın tam yolunu verir. Request.QueryString diyerek, sayfaya querystring ile gelen parametreleri alırız, veya Request.Cookies diyerek, daha önce tanımlanmış cookie değerlerine erişiriz. Bunları herhangi bir sayfada yazarken hiçbir sorun olmayız. Fakat, projenize bir class ekleyip, o class içinde herhangi bir yerde bunları çağırmayı deneyin.
Denediğiniz vakit, göreceksiniz ki, Intellisense yardımcı olmuyor. Ama herhangi bir sayfadan yazdığınızda eriştiğinizi göreceksiniz. Bunun nedeni, bu üyelerin Page sınıfında bulunması. Dolayısıyla sayfalarımız da Page sınıfından kalıtıldığından biz bu üyelere erişebiliyorduk. Sınıfımız Page sınıfından kalıtılmadığı için de dolayısıyla erişemiyoruz.
İşte bu sorunu ortadan kaldırmak için, Http requestlerine ulaşmamızı sağlayan HttpContext sınıfından Current property'si sayesinde, bize gelen Http Requestlerini dinleyebiliyoruz.
int id = Convert.ToInt32(HttpContext.Current.Request.QueryString["I_ID"]);
string username = HttpContext.Current.Request.Cookies["UserName"].ToString();
XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~\\data.xml"));
7 Temmuz 2011 Perşembe
Sql'de Truncate Table Kavramı
Sql'de bir tablomuzda bazı verileri silmek istediğimizde, Delete komutunu kullanırız. Başka bir alternatif yokturdur. Ama tablodaki tüm kayıtları silmek istersek, hem Delete, hem Truncate komutları sayesinde tüm tabloyu boşaltabiliriz.Yani Truncate komutu da Sql'de tüm tablodaki verileri boşaltmak amacıyla kullanılır.
Peki bu iki komut arasındaki fark nedir?
Kısaca, maddeler halinde yazalım.
Peki bu iki komut arasındaki fark nedir?
Kısaca, maddeler halinde yazalım.
- Öncelikle, Truncate kavramı ile bir şarta bakmaksızın tüm tablomuzu boşaltırız. Delete komutunda Where şartı ile belli şartlara bağlayabiliriz.
- Bence en önemli farklarından birisidir şimdiki maddemiz, Truncate Table yapınca, o tablodaki identity kolonumuz en baştan başlar. Ama Delete yaparsak, en son kaçıncı id'de kalmışsa, oradan devam eder.
- Truncate Table, Transaction içerisinde kullanılırsa ve işlemimiz rollback olursa geri alınamazlar. Delete komutunda geri alabiliriz.
- Truncate Table yaptığımızda, eğer o tablo üzerinde Delete Trigger'i varsa, bu trigger tetiklenmez. Delete komutlarında ise tetiklenir.
İşte Truncate Table ile Delete komutları arasındaki en temel fark bunlardır. Son olarak da syntaxlarını, nasıl yazıldıklarını gösterelim;
- TRUNCATE TABLE Tablo1
- DELETE FROM Table1
şart koymak istersek,
- DELETE FROM Table1 WHERE ID=5
Etiketler:
Sql,
Truncate Delete Arasındaki Fark,
Truncate Table
5 Temmuz 2011 Salı
İlişkili Tablolarda Veri Silme (Delete Join)
Şu ana kadar Joinleme işlemlerini ve Update Join işlemini görmüştük. Normal Joinleme işlemlerinde, birbiri ile ilişkili iki tablodan veri çekip, rahatlıkla istenilen raporu dökebiliyorduk. Daha sonra da, yine ilişkili tablolarda, gerekli şartları sağlayan kayıtları toplu halde update(Güncelleme) yapabiliyorduk. Bugün de, yine ilişkili tablolarda, belli şartları sağlayan verileri sileceğiz.
Örnek senaryomuz, AdventureWorks üzerinden AltKategorileri 'G' ile başlayan ürünleri silmek istensin bizden. Gördüğünüz gibi, tek tablo işimizi görmüyor. Product tablosundan kayıt sileceğiz ama, bu tablo üzerinden AltKategori isimlerine erişemiyoruz. İşte burada yapmamız gereken şey, iki tabloyu birleştirip, silme işlemini gerçekleştirmek. Bunun için yazmamız gereken kod şu şekilde olmalıdır;
Örnek senaryomuz, AdventureWorks üzerinden AltKategorileri 'G' ile başlayan ürünleri silmek istensin bizden. Gördüğünüz gibi, tek tablo işimizi görmüyor. Product tablosundan kayıt sileceğiz ama, bu tablo üzerinden AltKategori isimlerine erişemiyoruz. İşte burada yapmamız gereken şey, iki tabloyu birleştirip, silme işlemini gerçekleştirmek. Bunun için yazmamız gereken kod şu şekilde olmalıdır;
DELETE FROM Production.Product
FROM Production.Product p INNER JOIN Production.ProductSubcategory ps on p.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE ps.Name like 'G%'
Gördüğünüz gibi, önce hiçbir şart yokmuş gibi DELETE FROM Production.Product diyorum, daha sonra da belirtilen şartı sağlamak için joinleme işlemi yapıyorum. Bunun sonucunda, 6 kayıdın Product tablosundan silindiğini görürüz.
Not: Delete sorgusunu kullanarak, birden fazla tabloda veri silmek mümkün değildir. Bunun için birden fazla delete sorgusu çalıştırılmalıdır.
3 Temmuz 2011 Pazar
Sayfa Üzerinden MasterPage Değişikliği Yapmak
MasterPage kısaca, web uygulamalarında tüm web formların ortak özelliğini tutan ve onları sayfalarda gösteren bir mekanizmadır. İsterse 10 sayfamız olsun, tüm sayfalarda görünmesini istediğimiz bir alan varsa (genellikle header,footer ve sidemenu'ler olur) onları MasterPage ile üretip, tüm sayfalara uygularız. Peki, onlarca sayfadan sadece bir sayfa, bu master page'de belli bir alanı göstermek istetmezse?
Örneğin, MasterPage'imizde footer'ınde yazılan text'i sayfanın birinde değiştirelim. Bunun için yapmamız gereken şey, MasterPage'in code behind kısmında footer alanındaki Label'ın text'ini dışarıya setlemek olmak. Bunun için property yazmamız gerekecek. Yazacağımız property şu şekilde olmalı;
Burada bilmemiz gereken, herhangi bir sayfa üzerinde, Master diyerek LifeCycle sırasında üretilen MasterPage'in nesnesine ulaşırız. Buradan da az önce yazdığımız property'i değiştirdiğimiz zaman, artık bu sayfada masterpage'deki Footer kısmındaki text'i değiştirmiş oluruz. Dolayısıyla tüm sayfalarda MasterPage normal gözükürken, bu sayfamızda, Footer'da farklı bir yazı yazmış oldu. Farklı değişiklikler için de yine aynı yöntemle, değiştirmek istediğimiz kısımla ilgili property yazıp, onu dışarıya setlemeliyiz. Daha sonra da hangi sayfa üzerindeki MasterPage'i değiştirmek istersek, o sayfadan, MasterPage içerisine yazdığımız property'i cağırıp, gerekli değişiklikleri yaparız.
Örneğin, MasterPage'imizde footer'ınde yazılan text'i sayfanın birinde değiştirelim. Bunun için yapmamız gereken şey, MasterPage'in code behind kısmında footer alanındaki Label'ın text'ini dışarıya setlemek olmak. Bunun için property yazmamız gerekecek. Yazacağımız property şu şekilde olmalı;
public string FooterText
{
get { return Label1.Text; }
set { Label1.Text = value; }
}
Gördüğünüz gibi, Label'ın text'ini set bloğu içinde değiştirebilirtiyoruz. Bulunduğumuz sayfada da, MasterPage'in footer kısmındaki yazıyı şu şekilde değiştiririz;
((Main)Master).FooterText = "Bu MasterPage Kodla Değiştirildi";
29 Haziran 2011 Çarşamba
Stored Procedure'den Başka Bir SP Çağırmak (Output Parametresi)
Bazen sql ile geliştirme yaparken, birden fazla procedure ile çalışmak zorunda kalabiliriz.Yani bir procedure'in çalışmasıyla ortaya çıkan sonucu, diğer bir procedure içerisinde kullanabiliriz. Bu tarz durumlarda, yazılım dillerindeki fonksiyon mantığıyla, o procedure'ü çağırmamız gerekir. Oradan dönen sonucu da mevcut procedure'ümüzde kullanırız.
Şimdi ufak bir senaryo üzerinden devam edersek daha iyi anlaşılacaktır. Öğrenci tablomuz olsun. ÖğrenciEkle ismindeki Stored Procedure'müz, tablomuza kayıt atsın. Ayrıca OgrenciLog tablosuna da, hangi öğrenci kayıt atılırsa, onun id'sini ekleyelim. Aslında bu örnekte birden fazla sp'ye ve tabloya gerek yok ama, sadece birbiriyle olan ilişkileri göstermek amacıyla basit bir örnek olarak düşündüm. Normalde, birbirinden bağımsız, 30-40 kolonluk bir tablo olduğunu düşünebilirsiniz...
İlk procedure'müz basit olarak insert işlemi yapacak, ardından oluşacak id'yi de output parametresi yardımıyla, dışarıya aktaracağız. Yazacağımız sp kodu şu şekilde olmalıdır.
Şimdi ufak bir senaryo üzerinden devam edersek daha iyi anlaşılacaktır. Öğrenci tablomuz olsun. ÖğrenciEkle ismindeki Stored Procedure'müz, tablomuza kayıt atsın. Ayrıca OgrenciLog tablosuna da, hangi öğrenci kayıt atılırsa, onun id'sini ekleyelim. Aslında bu örnekte birden fazla sp'ye ve tabloya gerek yok ama, sadece birbiriyle olan ilişkileri göstermek amacıyla basit bir örnek olarak düşündüm. Normalde, birbirinden bağımsız, 30-40 kolonluk bir tablo olduğunu düşünebilirsiniz...
İlk procedure'müz basit olarak insert işlemi yapacak, ardından oluşacak id'yi de output parametresi yardımıyla, dışarıya aktaracağız. Yazacağımız sp kodu şu şekilde olmalıdır.
create procedure sp_OgrenciEkle
(
@Ad nvarchar(20),
@Soyad nvarchar(20),
@No bigint,
@Okul nvarchar(20),
@Id int output
)
as
begin
insert into Ogrenci values (@Ad,@Soyad,@No,@Okul)
set @Id = SCOPE_IDENTITY()
end
Şimdi OgrenciLog tablomuzu dolduracak procedure'mizde bu id output değerini alıp, tabloya yazalım. Bunu yaparken de, "sp_OgrenciEkle" isimli procedure'u çağırmamız gerekecek. Kodlama şu şekilde olmalıdır;
alter procedure sp_OgrenciLog
as
begin
declare @Id int
exec.sp_OgrenciEkle @Ad='Ergin',@Soyad = 'Arslan', @No=1234, @Okul='YTU' , @Id = @Id output
insert into OgrenciLog (OgrenciId) values (@Id)
end
Gördüğünüz gibi exec.Procedure_Adı diyerek procedure'e eriştim ve aldığı parametreleri değerleriyle birlikte yazarak, en son da geriye döndürdüğü değeri @Id isimli değişkenimize atıp, OgrenciLog tablomuza da değeri girmiş olduk. sp_OgrenciLog tablosunu çalıştırdığımız zaman, önce sp_OgrenciEkle procedure'u çalışacak, Ogrenci tablosuna kayıt attıktan sonra oluşan id'yi Scope_Identity() ile alıp output geçerek, bizim proc'umuza atacak ve biz de o değeri OgrenciLog tablomuza atacağız.
Dediğim gibi, böyle küçük örneklerde kullanılmaz output parametresi. Birden fazla procedurelar ile, 30-40 alanlı tablolara kayıt atarken, bazı alanları, bazı sp'lerin sonucundan almamız gerekebilir. İşte bu durumlarda, yukarıdaki gibi exec.SP_Adi diyip aldığı parametreleri değerleriyle birlikte, en sonda output parametresi olacak şekilde çalıştırırsak, o proc'un döndürdüğü değeri elde etmiş oluruz.
25 Haziran 2011 Cumartesi
Sql Recursive Functions(Rekürsif Fonksiyonlar)
Recursive fonksiyonlar, kendi kendini çağıran fonksiyonlardır. C#'ta da vardır, Java'da da , C'de de. Basit bir mantık, kendi işlemini yaptıktan sonra, tekrar kendi fonksiyonunu çağırması ve tekrar kendi içinde bulunan işlemleri tekrarlamasıdır. Sql'de de böyle bir işleme ihtiyacımız olabilir. Örneğin, bir kategori kendi içinde alt kategorileri olsun, o alt kategorilerin de altında başka kategoriler daha olsun. Gördüğünüz gibi, bir hiyerarşi oluşmuş. Biz sadece bir taban altına gitmemiz, doğru bir yaklaşım olmayacaktır. En alt katmana gelene kadar, kendi kendini sürekli çağırmalı ve gerekli işlemler yapılmalıdır.
Recursive fonksiyonlara verilebilecek en klasik örnek, faktöriyel hesabıdır. 5! dediğimiz zaman, önce 5 diyecek, daha sonra kendini çağırıp 5.4 olacak, daha sonra yine kendini çağırıp 5.4.3 diye diye 0 olana kadar bu kendini çağırma işlemi devam edecek.
Benzer senaryo, Sql'de de karşımıza gelebilir. Örneğin, AdventureWorks veritabanı üzerinde, HumanResources.Employee tablosunda, id'si 4 olan personelin bağlı olduğu şef, o şefin bağlı olduğu diğer şef, o şefin bağlı olduğu diğer şef ... vs. Genel Müdür gelene kadar bu işlem devam etmesini istiyorsak, gördüğünüz üzere bu hiyerarşik yapıyı kullanmak için recursive fonksiyon yazmamız gerekir. Kodlama aşağıdaki gibi olmalıdır;
Recursive fonksiyonlara verilebilecek en klasik örnek, faktöriyel hesabıdır. 5! dediğimiz zaman, önce 5 diyecek, daha sonra kendini çağırıp 5.4 olacak, daha sonra yine kendini çağırıp 5.4.3 diye diye 0 olana kadar bu kendini çağırma işlemi devam edecek.
Benzer senaryo, Sql'de de karşımıza gelebilir. Örneğin, AdventureWorks veritabanı üzerinde, HumanResources.Employee tablosunda, id'si 4 olan personelin bağlı olduğu şef, o şefin bağlı olduğu diğer şef, o şefin bağlı olduğu diğer şef ... vs. Genel Müdür gelene kadar bu işlem devam etmesini istiyorsak, gördüğünüz üzere bu hiyerarşik yapıyı kullanmak için recursive fonksiyon yazmamız gerekir. Kodlama aşağıdaki gibi olmalıdır;
with CTE as
(
select EmployeeID,ManagerID,Title from HumanResources.Employee
where EmployeeID=4 --baslangic id
union all
select HE.EmployeeID,HE.ManagerID,HE.Title from HumanResources.Employee HE join CTE
on HE.EmployeeID=CTE.ManagerID
)
select * from CTE
Sonuç kümesi de aşağıdaki gibi olur;
Kodlama hakkında bilgi vermek gerekirse, öncelikle CommonTableExpression yazmamız gerekir. Bunu herhangi bir yazılım dilindeki fonksiyonlara benzetebilirsiniz. Orada o fonksiyonu sürekli çağırırken, burada da sürekli CTE ile joinlediğimiz zaman, sürekli bir üst katmana gittiğini göreceğiz. Rekürsif fonksiyonlar, ikinci sorgumuz -CTE ile join yaptığımız- boş sonuç verene kadar devam eder. Ama bu işlem ciddi performans kayıplarına yol açmaması için, Sql Server default'u olarak 100 verilmiş. Yani en fazla 100 kez bu işlem devam edecektir. Ama biz en fazla kaç kere dönmesini de değiştirebiliriz. Bunun için yazmamız gereken kod, Select * from CTE'nin sonuna
OPTION(MAXRECURSION 4)
yazmak olmalıdır.
Sql Pivotlama Kavramı
Pivotlama, kısaca satırların sütuna taşınma işlemleridir. Özellikle kurumsal firmalarda, rapor çekilirken, raporun daha okunur kılınması için veya oluşacak binlerce satırlık raporu minimize etmek için pivotlama yöntemi kullanılır. 2005 öncesi case-when yapısı kullanılarak pivotlama işlemi yapılırken, 2005 sonrası dinamik pivotlama yardımıyla artık daha kolay yapmaktayız.
Şimdi kısaca bir senaryo uydurup, beraber pivotlama yöntemiyle sorgumuzu yazalım.
Senaryomuz kısaca, AdventureWorks database'i içinde departman bazında kaç erkek, kaç bayan çalıştığını bulalım. Normal sorgulamamızı yaparsak önce departmanlara göre kaç bayan var, sonra yine departmanlara göre kaç erkek var alt alta göreceğiz, dolayısıyla satır sayısı fazla, okunulurluğu yok. Nasıl oluştuğunu görelim önce.
Sorgumuzu yazmak için 3 tabloya ihtiyacımız var. Bunlar Department, Employee ve EmployeeDepartmentHistory. Bunları birbirine joinledikten sonra cinsiyet ve departmana göre group by yapıp toplam sayı bizim istediğimiz sonuc olacak. Burada yeri gelmişken, kısaca sql'in kendi editöründen nasıl joinleme işlemlerini kolayca yapabileceğimizi göstereyim. Sorgu sayfasında herhangi bir yere sağ tıklayıp design query in editor dedikten sonra önümüze bir ekran gelecek. Add Table penceresinden yukarıda bahsettiğim üç tabloyu seçtiğimizde önümüze şu şekilde bir diyagram getirecek.
Şimdi kısaca bir senaryo uydurup, beraber pivotlama yöntemiyle sorgumuzu yazalım.
Senaryomuz kısaca, AdventureWorks database'i içinde departman bazında kaç erkek, kaç bayan çalıştığını bulalım. Normal sorgulamamızı yaparsak önce departmanlara göre kaç bayan var, sonra yine departmanlara göre kaç erkek var alt alta göreceğiz, dolayısıyla satır sayısı fazla, okunulurluğu yok. Nasıl oluştuğunu görelim önce.
Sorgumuzu yazmak için 3 tabloya ihtiyacımız var. Bunlar Department, Employee ve EmployeeDepartmentHistory. Bunları birbirine joinledikten sonra cinsiyet ve departmana göre group by yapıp toplam sayı bizim istediğimiz sonuc olacak. Burada yeri gelmişken, kısaca sql'in kendi editöründen nasıl joinleme işlemlerini kolayca yapabileceğimizi göstereyim. Sorgu sayfasında herhangi bir yere sağ tıklayıp design query in editor dedikten sonra önümüze bir ekran gelecek. Add Table penceresinden yukarıda bahsettiğim üç tabloyu seçtiğimizde önümüze şu şekilde bir diyagram getirecek.
Yukarıda da görüldüğü gibi, bize sadece Gender ve Name kolonu gerektiğinden sadece onları seçiyoruz. Tabloların altında sql'in bizim için kodu kendi oluşturduğunu görüyoruz.Daha sonra oluşan kodu çalıştırdığımız zaman aşağıdaki şekilde bir sonuç kümesi geleceğiniz görürüz.
Ama biz bunu pivotlama yöntemiyle yaparsak, aşağıdaki gibi sorgu yazmamız gerekecekti. Sorgunun mantığını aşağıda anlatacağım. Önce ortaya çıkan rapor'a bakalım,
Yazacağımız kod da şu şekilde olmalıdır.
WITH CTE
as
(
SELECT Department.Name as Departman,Employee.Gender as Cinsiyet,COUNT(HumanResources.Employee.EmployeeID) [count] FROM HumanResources.Department
INNER JOIN HumanResources.EmployeeDepartmentHistory ON HumanResources.Department.DepartmentID = HumanResources.EmployeeDepartmentHistory.DepartmentID
INNER JOIN HumanResources.Employee ON HumanResources.EmployeeDepartmentHistory.EmployeeID = HumanResources.Employee.EmployeeID
group by Gender,Department.Name,Department.ModifiedDate
)
select * from CTE PIVOT (SUM([count]) for Cinsiyet in ([F],[M])) as p
Önce CommonTableExpression ile bir tablo oluşturuyoruz. Aslında bizim pivotsuz kodumuz budur. Zaten yukarıdaki resimden de query editorun yazdığı koddan karşılaştırabilirisiniz.Bu CTE'yi yazdıktan sonra bu tablodan select * from'la tüm verileri alıyoruz fakat, 2005 yılından sonra gelen PIVOT konumu ile toplam kayıt sayısına göre Cinsiyetleri üst kolona köşeli parantez içinde yazarak kolonlara taşımış oluyoruz.
Not: En sondaki yazdığımız select sorgusunun sonuna as p diyerek bir alias veriyoruz. Bu Sql'in gözden kaçırdığı veya neden böyle bir şeyi yaptırmaya mecbur tuttuğunu anlamadığım bir zorlamasıdır. Pivotlama yaptıktan sonra, yazdığımız o sorguya alias vermek zorundayız. Aksi taktirde hata mesajı verecektir. Bu yüzden rasgele bir alias verebilirsiniz, zira daha sonra herhangi bir yerde kullanılmayacaktır.
Asp.Net'de IIS Hatası
Yazdığımız web sayfasını IIS'imize ekledikten sonra, çalıştırmak istediğimizde şu hatayı alırsak;
İstediğiniz sayfa uzantı yapılandırması nedeniyle sunulamıyor. Sayfa bir komut dizisi ise, bir işleyici ekleyin. Dosyanın karşıdan yüklenmesi gerekiyorsa, bir MIME eşlemesi ekleyin.
anlamalıyız ki, IIS'imiz aspx sayfalarını tanımıyor. Bunu düzeltmemiz için yapmamız gereken şey;
Başlat-Tüm Programlar-Microsoft Visual Studio 2010- Visual Studio Tools - Command Prompt 2010 'u açıp,
aspnet_regiis -i yazmak olmalıdır.
Eğer hata olarak, admin olarak girin tarzı bir hata gelirse,
run cmd diyip,
cd c:\Program Files (x86)\Microsoft Visual Studio 2010\VC
yazıp, tekrar
aspnet_regiis -i yazmalıyız.
Bu yaptıklarımızla, aspx dosyalarını iis'e yüklemiş oluruz. Artık localhost\sayfa.aspx dersek, sayfamızın açıldığını görürüz.
6 Haziran 2011 Pazartesi
LinqToXml
Xml, -eXtensible Markup Language- kısacası verileri elde etmek için, taşımak için vs. platform bağımsız çalışabilen, yani javacısı c#'cısı, php'cisi tarafından kullanılan bir işaretleme dilidir. Günlük hayatımızda sıkça xml dosyaları ile uğraşırız. Ya xml dosyasından veri okuruz, veya kendi xml'imizi okuyup, başka servislerin kullanımına sunarız. İşte bu Xml okuma ve yazma işlemlerini inceleyeceğiz birazdan.
C# 3.0 ile birlikte gelen LINQ teknolojisiyle, bu işlem daha da kolaylaşmış oldu. Artık onlarda satırlık xml oluşturma işlemini tek satıra bile sığdırabiliyoruz. Şimdi sırasıyla Xml okuma, güncelleme ve oluşturma işlemlerini Linq teknolojisini kullanarak örneklemeye çalışacağım.
Öncelikle bir xml dosyası oluşturup, buradan verileri okuyalım. Oluşturacağımız Urunler.xml dosyası aşağıdaki gibi olsun.
1-Xml Okuma: Öncelikle xml dosyasını yüklememiz gerekecek.
Xml dosyamızı yükledikten sonra, artık tagler içinde dolaşabiliriz. Xml formatı gereği, en dışta tek element bulunması gerekir. Onun içinde birden fazla element bulunabilir ama. Buna göre, yazacağımız kodlarda şu iki metodu çok iyi bilmemiz gerekecek;
Element() ve Elements() Metotları...
Adım adım xml dosyasında dolaştığımızdan, en dıştan içe doğru girerken, önce kök elementini göreceğiz. Ürünler xml'inde tag'i bizim için kök elementtir. Yani tektir. Bu yüzden Element("Urunler") metodunu kullanmalıyız. Ardından birden fazla Urun olduğundan, Element("Urun") metodunu kullanacağız. Yani;
Bu yazdığımız kod, geriye IEnumerable döndürür. Yani bir sorgudur bu yazdığımız kod. Bu sorgunun içinde foreach ile gezersek, Tüm ürün sınıfının altındaki elementlere ulaşmış olacağız. Yani ;
Bir örnek daha yazalım, daha anlaşılır olsun. Fiyatı 100'den küçük olan kaç tane ürün olduğunu ekrana yazdıralım.
2-Xml Oluşturma : Yine aynı şekilde xml'imizi yükleyelim.
Yukarıda da anlayacağınız gibi, kök elementimize tek bir ürün elementi ekledik (XElement). Urun tag'inin içine de ID,Ad ve Fiyat elementlerini virgülle ayrılacak şekilde yazdık. Alt satıra geçmesi kafa karıştırmasın, tamamiyle kod okulurluğu sağlanması amaçtır. buna göre xml'imize Urun tagi içinde ID,Ad ve Fiyat bilgileri de eklenmiş olacaktır.
3-Xml Güncelleme: Diğer iki işlemlere göre daha basit bir işlem gerektirecek. Direk örnek üzerinden anlatmaya çalışacağım, anlaşılır olacaktır.
Önce id'si 1 olan ürünü getirip, SetElementValue metodunu kullanarak, Fiyat'ını 400 yaptık. Oldukça basit bir işlem.
Gördüğünüz gibi LINQ to XML ile, xml dosyası oluşturmak, var olan dosyada gerekli değişiklikler yapmak veya dosyadan veri okumak oldukça kolaylaştı. Eski yöntemlerde hata yapma oranı oldukça fazla olmasının yanında, onlarca satırlık kodu, 2-3 satıra sığdırmış olacağız. Bu konuyu öğrenmekte büyük fayda var, çünkü xml her ortamda karşımıza çıkacak olan bir konudur. Eğer linq biliyorsanız veya bilmeseniz bile kodları biraz kurcalamanız sonucunda rahatlıkla, verilen işlemleri yapabilir duruma geleceksiniz.
C# 3.0 ile birlikte gelen LINQ teknolojisiyle, bu işlem daha da kolaylaşmış oldu. Artık onlarda satırlık xml oluşturma işlemini tek satıra bile sığdırabiliyoruz. Şimdi sırasıyla Xml okuma, güncelleme ve oluşturma işlemlerini Linq teknolojisini kullanarak örneklemeye çalışacağım.
Öncelikle bir xml dosyası oluşturup, buradan verileri okuyalım. Oluşturacağımız Urunler.xml dosyası aşağıdaki gibi olsun.
1-Xml Okuma: Öncelikle xml dosyasını yüklememiz gerekecek.
XDocument doc = XDocument.Load("..\\..\\Urunler.xml");
Xml dosyamızı yükledikten sonra, artık tagler içinde dolaşabiliriz. Xml formatı gereği, en dışta tek element bulunması gerekir. Onun içinde birden fazla element bulunabilir ama. Buna göre, yazacağımız kodlarda şu iki metodu çok iyi bilmemiz gerekecek;
Element() ve Elements() Metotları...
Adım adım xml dosyasında dolaştığımızdan, en dıştan içe doğru girerken, önce kök elementini göreceğiz. Ürünler xml'inde
doc.Element("Urunler").Elements("Urun");
Bu yazdığımız kod, geriye IEnumerable
foreach (XElement urun in doc.Element("Urunler").Elements("Urun"))
{
Console.WriteLine("{0}-{1}", urun.Element("ID").Value, urun.Element("Ad").Value);
}
Bir örnek daha yazalım, daha anlaşılır olsun. Fiyatı 100'den küçük olan kaç tane ürün olduğunu ekrana yazdıralım.
Console.WriteLine(doc.Root.Elements().Count(s => int.Parse(s.Element("Fiyat").Value) < 100));
2-Xml Oluşturma : Yine aynı şekilde xml'imizi yükleyelim.
XDocument doc = XDocument.Load("..\\..\\Urunler.xml");
Yine mantık aynı. en dışta kök elementi, ardından ürün sayısı kadar alt elementler oluşacak. Eğer kök elementinin içinde tek element varsa new Element() ile tek bir element oluşturuyoruz, birden fazla var ise new Elements() diyip yeni elementleri parametre olarak veriyoruz. Örnekte daha da iyi anlaşılacaktır.
XElement yeni = new XElement("Urun",
new XElement("ID", 4),
new XElement("Ad", "Laptop"),
new XElement("Fiyat", 1000));
doc.Root.Add(yeni);
Yukarıda da anlayacağınız gibi, kök elementimize tek bir ürün elementi ekledik (XElement). Urun tag'inin içine de ID,Ad ve Fiyat elementlerini virgülle ayrılacak şekilde yazdık. Alt satıra geçmesi kafa karıştırmasın, tamamiyle kod okulurluğu sağlanması amaçtır. buna göre xml'imize Urun tagi içinde ID,Ad ve Fiyat bilgileri de eklenmiş olacaktır.
3-Xml Güncelleme: Diğer iki işlemlere göre daha basit bir işlem gerektirecek. Direk örnek üzerinden anlatmaya çalışacağım, anlaşılır olacaktır.
//1 idli ürünün fiyatını değiştirelim 400 olsun
XElement urun = doc.Root.Elements().FirstOrDefault(s => s.Element("ID").Value == "1");
urun.SetElementValue("Fiyat", 400);
Önce id'si 1 olan ürünü getirip, SetElementValue metodunu kullanarak, Fiyat'ını 400 yaptık. Oldukça basit bir işlem.
Gördüğünüz gibi LINQ to XML ile, xml dosyası oluşturmak, var olan dosyada gerekli değişiklikler yapmak veya dosyadan veri okumak oldukça kolaylaştı. Eski yöntemlerde hata yapma oranı oldukça fazla olmasının yanında, onlarca satırlık kodu, 2-3 satıra sığdırmış olacağız. Bu konuyu öğrenmekte büyük fayda var, çünkü xml her ortamda karşımıza çıkacak olan bir konudur. Eğer linq biliyorsanız veya bilmeseniz bile kodları biraz kurcalamanız sonucunda rahatlıkla, verilen işlemleri yapabilir duruma geleceksiniz.
24 Mayıs 2011 Salı
Sql'de İlişkili Tablolarda Güncelleme(Update-Join)
Sql'de update işlemleri yaparken, şu ana kadar hep tek tablo üzerinden yaptık. Peki, birbiriyle ilişkili birden fazla tabloda update işlemi yaparsak nasıl bir yol izleyeceğiz?
Cevap oldukça basit. Biz yine de daha anlaşılır olması bakımından, senaryo üzerinden gidelim. İki tablomuz olsun. Öğrenci tablosunda Numara ve Ad tutulsun, Not tablosunda da ÖgrenciNo ve Puan tutulsun.
create Table Ogrenci
(
OgrenciNo int,
OgrenciAd nvarchar(20)
)
create Table Puan
(
OgrenciNo int,
Puan int
)
update Puan set Puan=50 from Puan p join Ogrenci o on p.OgrenciNo=o.OgrenciNo where OgrenciAd='Ahmet Demir'
Cevap oldukça basit. Biz yine de daha anlaşılır olması bakımından, senaryo üzerinden gidelim. İki tablomuz olsun. Öğrenci tablosunda Numara ve Ad tutulsun, Not tablosunda da ÖgrenciNo ve Puan tutulsun.
create Table Ogrenci
(
OgrenciNo int,
OgrenciAd nvarchar(20)
)
create Table Puan
(
OgrenciNo int,
Puan int
)
OgrenciNo alanı, Ogrenci tablosunda PrimaryKey iken, Puan tablosunda ForeignKey'dir. Böylece iki tabloyu ilişkilendirmiş olduk.
Birkaç kayıt girdikten sonra senaryomuz şöyle olsun. İsmi Ahmet Demir olan öğrencinin Puanını 50 yapalım. Gördüğünüz gibi tek tabloda update işlemi yapıyor olmamıza rağmen, verilen koşul başka bir tabloda. Burada iki tabloyu join ile birleştirip, ardından update işlemini yapacağız. Yazmamız gereken kod şu şekilde olmalıdır.
update Puan set Puan=50 from Puan p join Ogrenci o on p.OgrenciNo=o.OgrenciNo where OgrenciAd='Ahmet Demir'
Gördüğünüz üzere, syntax olarak, select ile yapılan joinleme işlemine çok benzer. select * from Puan ile başlayan joinleme sorgumuz, burada update Puan set Puan=50 from Puan olmuştur. Sorgu sonucunda, ismi Ahmet Demir olan öğrenci/öğrenciler 'in aldığı puanlar 50 olarak güncellenmiştir.
18 Mayıs 2011 Çarşamba
Windows Formlarda Custom Control
Windows Formlar uzerinde uygulama gelistirirken, bazi durumlarda kendi kontrollerimizi oluşturmak isteriz. Örneğin, uygulamanızdaki tüm TextBox'lar sadece nümerik değerler girilmesi isteniyorsa, yapmamız gereken tüm textbox'lar için ayrı ayrı kod yazmak. Daha sonra değişiklik istendiğinde de 30 textbox varsa, 30'unda birden tekrar değişikliği gerçekleştirmek gerekecek. Bir kod kendini gereksiz yere, fazlasıyla tekrar ediyorsa şunu bilmeliyiz ki, o kod yanlıştır. Şimdi bu örnek için kendi TextBox'ımızı yaratıp, tüm sayfalarda bu TextBox'ı sürükleyip bırakarak, gereksiz kodlamanın önüne geçmiş olacağız.
Kodlamaya gelirsek, düşünmemiz gereken şey, oluşturucağımız TextBox'ın, TextBox sınıfından kalıtılması olmalıdır, çünkü tüm özellikleri normal TextBox ile aynı olacak. Sadece ekleyeceğimiz şeyler olacak.
O zaman uygulamamıza yeni bir class ekleyip, onu TextBox sınıfından kalıtalım.
Uygulamamızı çalıştırdığımız zaman göreceğiz ki, oluşturduğumuz TextBox'ın, diğer TextBox'lardan görünüm ve görev bakımından hiçbir farkı yok, ekstra olarak sadece rakamlara ve delete,ctrl,backspace tarzı kontrollere izin verecektir. Artık, tüm sayfalarımızda, bu TextBox'ı sürükleyip bırakarak rahatça erişebileceğimiz gibi, değişiklik yapmak istediğimiz zaman da tek bir yerden düzeltmelerimizi yapabileceğiz.
Kodlamaya gelirsek, düşünmemiz gereken şey, oluşturucağımız TextBox'ın, TextBox sınıfından kalıtılması olmalıdır, çünkü tüm özellikleri normal TextBox ile aynı olacak. Sadece ekleyeceğimiz şeyler olacak.
O zaman uygulamamıza yeni bir class ekleyip, onu TextBox sınıfından kalıtalım.
class NumericTextBox:TextBox
Daha sonra NumericTextBox sınıfının constructor'ında, senaryomuzu yerine getirecek eventi bulup, onu tetikliyoruz. Bu örnek için, nümerik karakter haricinde başka bir karakter girilmesin, sadece nümerik karakterlerin girişine izin verilmesini istiyorsak, kullanacağımız event KeyPress eventi olmalıdır. Bu eventi tetikledikten sonra, girilmesini istemediğimiz karakter kodlarını girip, programımızı çalıştıracağız. Yazacağımız kod şu şekilde olacaktır;
class NumericTextBox:TextBox
{
public NumericTextBox()
{
this.KeyPress += new KeyPressEventHandler(NumericTextBox_KeyPress);
}
void NumericTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsNumber(e.KeyChar) && !char.IsControl(e.KeyChar); //rakam degilse giris yapamasin ve backspace,delete tarzi kontrollere de izin verilmesin
}
}
Şunu da hatırlamakta fayda var. Oluşturacağımız bir class'ı, herhangi bir kontrolden kalıttığımız zaman, bu classın(yani yeni kontrolümüzün-custom control-) toolbox'da en yukarıda oluşacağını hatırlatmakta fayda var.
Uygulamamızı çalıştırdığımız zaman göreceğiz ki, oluşturduğumuz TextBox'ın, diğer TextBox'lardan görünüm ve görev bakımından hiçbir farkı yok, ekstra olarak sadece rakamlara ve delete,ctrl,backspace tarzı kontrollere izin verecektir. Artık, tüm sayfalarımızda, bu TextBox'ı sürükleyip bırakarak rahatça erişebileceğimiz gibi, değişiklik yapmak istediğimiz zaman da tek bir yerden düzeltmelerimizi yapabileceğiz.













