Selasa, 03 Januari 2012

3-Tier Architecture

Dalam menghadapi kompleksitas kita perlu menggunakan politik Belanda waktu menjajah Indonesia "Devide et Impera", pecah belah lalu kuasai. Ketika membangun aplikasi yang kompleks , ada baiknya kita "memecah belah" aplikasi menjadi 3 layer. Pemisahan ini bisa jadi hanya secara logik (software), tidak harus berkorespondensi secara fisik (hardware). Masih ingat arsitektur TCP/IP yang dibuat berlapis-lapis? kira-kira apa tujuannya? pemisahan arsitektur aplikasi menjadi beberapa layer dimaksudkan untuk meminimalkan terjadinya ripple effect. Efek ini terjadi jika sebuah modul sangat tergantung dengan modul yang lain, sehingga jika terjadi perubahan disatu sisi, sisi lain harus ikut diubah. Istilah kerennya adalah tighty couple

Pada pendekatan 3-tier architecture aplikasi ini dipecah menjadi 3 layer yaitu : Presentation, Business Logic dan Data Access layer. Pemecahan ini tidak harus berkorespondensi secara fisik (hardware), bisa jadi hanya secara logik (software).

Presentation layer bertanggung jawab dengan tampilan (user interface), Business Logic dengan logika business/domain permasalahan dan Data Access bertanggung jawab bagaimana mekanisme akses ke basis datanya. Dengan pemisahan ini aplikasi tidak tergantung dengan user interface nya apa (Console, WinForm, Web/ASP.NET) atau pilihan DBMS (SQL Server, Oracle, MySQL), sehingga apabila terjadi perubahan dikemudian hari karena suatu hal, developer tidak harus menulis ulang program dari awal.

Perbedaan 1-Tier dengan 3-Tier
   1.  Classic (1-Tier)                                                               
  • Semua kode (SQL dan C#) diletakkan disatu tempat, yaitu di bagian user interface.
  • Terjadi pengulangan penulisan program atau syntax SQL, sehingga ada banyak duplikasi kode

  • Struktur program tidak teratur
  • Jika terjadi perubahan user interface, maka program harus ditulis ulang
  2.  Classic (3-Tier)
  • Kode dipecah menjadi 3 layer sesuai dengan fungsi dan tanggung jawabnya
  • Method-method yang sudah dibuat tinggal dipanggil, sehingga class dapat di reusable (penggunaan ulang kembali)
  • Program lebih modular dan mudah dibaca

ADO.NET Lanjut (Generic Data Access)

ADO.NET menyediakan beberapa namespace berbeda untuk pengaksesan database. Seperti yang telah saya jelaskan di Pengenalan ADO.NET, setiap mengubah database kita harus mengubah juga namespacenya misal jika menggunakan database MS Access , maka namespace yang digunakkan adalah System.Data.OleDb, dan SQL Server : System.Data.OracleClient.

Celakanya, bukan hanya namespace yang diubah, class class didalam namespace tersebut juga harus berubah.
Contoh :
                OleDbConnection  ========> SqlConnection
                OleDbCommand   ========> SqlCommand
                OleDbDataReader ========> OleDbDataReader

Lalu dimanakah permasalahnnya?bukankah masing-masing class di namespace tersebut memiliki cara akses yang sama. Dari sudut pandang Software Engineering, jika ingin membuat aplikasi yang scalable dan dinamis, kita harus memikirkan desain arsitektur yang "tahan banting". Perubahan adalah salah satu hal yang tidak bisa dihindari dalam Software Development karenanya kita harus mempertimbangkan berbagai aspek yang kemungkinan bisa terjadi dikemudian hari. Karena fokus kita kali ini di database, saya hanya akan membahas bagaimana cara mensiasati jika dikemudian hari terjadi pergantian DBMS karena alasan tertentu. Salah satu solusi untuk mengatasi perubahan DBMS adalah dengan membuat generic data access agar program tidak tergantung dengan database tertentu. Sehingga jika terjadi pergantian DBMS tidak akan ada perubahan signifikan.

.NET Framework menyediakan namespace System.Data.Common untuk pembuatan generic data access. Namespace tersebut memiliki class-class berikut.


  • DbProviderFactory  (Pembuatan instance provider data source spesifik)
  •  DbConnection (Membuka koneksi)
  •  DbCommand (Eksekusi perintah SQL)
  •  DbDataReader (Menampilkan data)
  •  DbDataAdapter (Penghubung ke DataSet)
Saya hanya akan membahas class-class utama saja dalam namespace tersebut. Class utama dalam namespace tersebut adalah DBProviderFactory.Class ini bertanggungjawab terhadap pembuatan instance dari provider data source yang diinginkan.

Contoh :
MS Access
string driver = "System.Data.OleDb";
string connStr = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=c:\\NWIND.mdb";

DbProviderFactory factory = DbProviderFactories.GetFactory(driver);
DbConnection conn = factory.CreateConnection();
conn.ConnectionString = connStr; conn.Open();

Data source pada contoh diatas menggunakan MS Access, sehingga namespace yang digunakan adalah System.Data.OleDb dan Connection string nya untuk MS Access jika ingin menggantinya ke SQL Server maka yang perlu diubah cukup driver dan connection string nya.

SQL Server


string driver = "System.Data.SqlClient";
string connStr = "Data Source= SYSTEMINTERFACE\\SQLEXPRESS;"
                          + "Initial Catalog=NWIND;Integrated Security=True";
DbProviderFactory factory = DbProviderFactories.GetFactory(driver);
DbConnection conn = factory.CreateConnection();
conn.ConnectionString = connStr;
conn.Open();

Yang menarik disini driver,dan connStr diperlakukan sebagai string, sehingga informasi ini bisa kita simpan dalam bentuk konfigurasi di XML.Dengan demikian jika terjadi perubahan implentasi database program tidak usah di compile ulang, cukup dengan mengubah konfigurasi XML nya. Bayangkan sebuah aplikasi client-server skala enterprise yang client nya bisa jadi terdiri dari banyak sekali komputer, compile ulang dan mendistribusikan kembali program tersebut ke client. Hmmm..jujur saja saya tidak akan mau melakukan ini !. Jika kita simpan dalam bentuk XML, file konfigurasi ini bisa disimpan diserver. Jika terjadi perubahan cukup mengedit file XML tersebut 1 kali, dan client tidak usah disentuh sama sekali

INSERT



DbCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO Customers (CustomerID,CompanyName) VALUES "
                                   + "(@CustId,@Name)";

DbParameter param1 = cmd.CreateParameter();
param1.ParameterName ="@CustId";
param1.Value="XERIS";

DbParameter param2 = cmd.CreateParameter();
param2.ParameterName ="@Name";
param2.Value="XERIS System Interface";

cmd.Parameters.Add(param1);
cmd.Parameters.Add(param2);

cmd.ExecuteNonQuery();

UPDATE



DbCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
cmd.CommandText = "UPDATE Customers SET CompanyName=@Name "
                                 + "WHERE CustomerID=@CustId";

DbParameter param1 = cmd.CreateParameter();
param1.ParameterName = "@CustId";
param1.Value = "XERIS";

DbParameter param2 = cmd.CreateParameter();
param2.ParameterName = "@Name";
param2.Value = "XERIS System Interface";

cmd.Parameters.Add(param1);
cmd.Parameters.Add(param2);

cmd.ExecuteNonQuery();

DELETE


DbCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
cmd.CommandText = "DELETE FROM Customers WHERE CustomerID=@CustId";

DbParameter param1 = cmd.CreateParameter();
param1.ParameterName = "@CustId";
param1.Value = "XERIS";

cmd.Parameters.Add(param1);
cmd.ExecuteNonQuery();

 SELECT

DbCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT * FROM Customers WHERE CompanyName LIKE @Name";

DbParameter param1 = cmd.CreateParameter();
param1.ParameterName = "@CustId";

param1.Value = "XERIS";
cmd.Parameters.Add(param1);
IDataReader rdr = cmd.ExecuteReader();

while (rdr.Read())
  {
     Console.WriteLine(rdr["CustomerID"]);
     Console.WriteLine(rdr["CompanyName"]);
   }
rdr.Close();

 Lalu bagaimana kalau konfigurasi data source nya diletakkan di XML? .NET Framework menyediakan akses ke konfigurasi XML lewat namespace System.Configuration. Class yang digunakan adalah ConfigurationManager

perhatikan contoh berikut :


string driver = ConfigurationManager.AppSettings["Driver"];
string connStr = ConfigurationManager.AppSettings["ConnectionString"];

 Sedangkan konfigurasi XML disimpan di file App.config



<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Driver" value="System.Data.SqlClient"/>
<add key="ConnectionString" value="Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=True"/>
</appSettings>
</configuration>

 Agar dapat menakses konfigurasi XML di App.config tambahkanlah library System.configuration menggunakan IDE Microsoft Visual C# 2005 Express Edition Anda melalui menu Project->Add Reference.

Stored Procedure

Stored Procedure adalah procedure yang terletak di DBMS yang dapat dipanggil oleh aplikasi baik secara local ataupun lewat jaringan. Stored Procedure merupakan salah satu fitur utama DBMS bertipe client-server seperti SQL Server dan Oracle. Berikut ini manfaat menggunakan Stored Procedure :
  • Diletakan di server, stored procedure biasanya digunakan untuk menuliskan business logic. Jika terjadi perubahan cukup merubahnya di server.
  • Memiliki keamanan yan lebih baik. Karena diakses di server, aplikasi yang menggunakan stored procedure akan terhindar dari upaya hacking seperti SQL Injection.
  • Membuat program yang lebih modular
  • Dapat menurunkan trafik jaringan
Contoh Stored Procedure

CREATE PROCEDURE [dbo].[spInsertCustomer]
   @CustomerID varchar(5) ,
   @CompanyName varchar(50),
   @Address varchar(200)
AS
BEGIN
INSERT INTO Customers (CustomerID,CompanyName,Address) VALUES (@CustomerID,@CompanyName,@Address)
END

Cata mengaksesnya :


SqlCommand cmd=new SqlCommand(sql,conn);

cmd.CommandText="spInsertCustomer";
cmd.CommandType=CommandType.StoredProcedure;

DbParameter param1 = cmd.CreateParameter();
param1.ParameterName ="@CustomerID";
param1.Value="XERIS";

DbParameter param2 = cmd.CreateParameter();
param2.ParameterName ="@CompanyName";
param2.Value="XERIS System Interface";

DbParameter param3 = cmd.CreateParameter();
param3.ParameterName ="@Address";
param3.Value="JEDAH";

cmd.Parameters.Add(param1);
cmd.Parameters.Add(param2);
cmd.Parameters.Add(param3);

cmd.ExecuteNonQuery();


Transaction

Transaksi didefenisikan sebagai himpunan satu atau lebih pernyataan yang diekseskusi sebagai satu unit, dengan demikian dalam suatu transaksi himpunan pernyataan harus dilaksanakan atau tidak sama sekali. Contoh jika kita ingin menghapus record yang memiliki hubungan master-detail. Proses penghapusan record di tabel master harus disertai dengan record yang berelasi di tabel detail, jika proses penghapusan record pada tabel master gagal proses penghapusan harus dibatalkan seluruhnya agar integritas data tetap terjaga.

Contoh Code


string connStr="Data Source=SYSTEMINTERFACE\\SQLEXPRESS;Initial Catalog=NWIND;"
                                              + "Integrated Security=True";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlTransaction tx = conn.BeginTransaction();
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.Transaction = tx;
try
     {
        cmd.CommandText = "DELETE Orders WHERE OrderID=1";
         cmd.ExecuteNonQuery();
         cmd.CommandText = "DELETE OrderDetails WHERE OrderID=1";
        cmd.ExecuteNonQuery();
        tx.Commit();
      }
catch (SqlException ex)
    {
      Console.WriteLine(ex.Message.ToString());
       tx.Rollback();
      }

DataSet

DataSet adalah tabel virtual yang tersimpan di memory. DataSet merupakan fitur unggulan ADO.NET yang menyediakan pengaksesan data bisa dilakukan secara disconnected, tanpa harus selalu terhubung ke database. 

Keuntungan menggunakan DataSet :
  • Flexibility, DataSet mengandung koleksi dari data dan dapat merepresentasikan relasi yang kompleks
  •  Serialization, DataSet mendukung serialisasi yang biasanya digunakan untuk distributed application
  • Data Binding, DataSet dapat di ikatkan ke komponen-komponen yang bersifat “data aware” baik pada WinForm (GUI) atau WebForm (ASP.NET)
  • Sorting dan Filtering, DataSet mendukung sorting dan filtering data dengan menggunakan DataView Object.
  • Interchangeability, DataSet dapat dibaca dan diubah dalam format XML sehingga data bisa diakses walaupun koneksi sudah terputus (disconnected application) .
  • Optimistic Concurrency, Ketika melalkukan pengupdate-an data DataSet dapat digunakan bersama DataAdapter yang memungkinkan concurrency check dilakukan dengna mudah
  • Extensibility, Schema dari DataSet bisa diubah secara runtime
Contoh penggunaan DataSet


string sql = "SELECT * FROM Customers";
DataSet ds = new DataSet(); 
SqlDataAdapter adapter = new SqlDataAdapter(sql, conn); adapter.Fill(ds);
foreach (DataRow row in ds.Tables[0].Rows) 
   { 
      Console.WriteLine(row["CustomerID"]); Console.WriteLine(row["CompanyName"]); 
    }




Menggunakan ADO.NET

Ketika kita berhubungan dengan basis data menggunakan ADO.NET “ritual” nya adalah sebagai berikut :
1. Membuka Koneksi
Hal pertama yang harus dilakukan untuk membuat aplikasi database adalah membuka koneksi. Koneksi ini selalu diperlukan untuk menjalankan operasi-operasi manipulasi data seperti INSERT, UPDATE dan DELETE ataupun meng-query record tertentu dengan perintah SELECT. Class yang bertugas untuk membuka koneksi adalah OleDbConnection untuk MS Access, dan SqlConnection untuk SQL Server. OleDbConnection dan SqlConnection membutuhkan property ConnectionString yang harus diisi. Selain lewat property Connection String bisa ditambahkan juga sebagai parameter constructor class. Connection String tiap database berbeda-beda. Connection String ini menunjukan provider DBMS yang digunakan beserta letak direktori dan nama database nya baik lokal maupun remote database Contoh source code untuk buka koneksi :

MS Access :

string connStr="Provider=Microsoft.Jet.OleDb.4.0;Data Source=c:\\NWIND.mdb"; 
OleDbConnection conn=new OleDbConnection(connStr); 
conn.Open();

atau bisa seperti ini :

string connStr="Provider=Microsoft.Jet.OleDb.4.0;Data Source=c:\\NWIND.mdb"; 
OleDbConnection conn=new OleDbConnection();
conn.ConnectionString=connStr; conn.Open();

SQL Server :

string connStr="Data Source=SYSTEMINTERFACE\\SQLEXPRESS;Initial Catalog=NWIND;" 
                                              + "Integrated Security=True";
SqlConnection conn=new SqlConnection(connStr); 
conn.Open();

Data Source pada ConnStr diisi nama server lokal atau bisa diisi IP Address jika menggunakan server remote.

2. Eksekusi Perintah SQL
Setelah koneksi terbuka, langkah berikutnya adalah memanggil perintah SQL yang akan dieksekusi. SQL (Structure Query Language) adalah bahasa yang digunakan untuk berkomunikasi dengan DBMS. Tanpa perintah SQL user tidak dapat melakukan apapun terhadap Database.

Perintah SQL berbeda dengan bahasa pemrograman, SQL sifatnya deklaratif dan lebih mudah dimengerti secara sintaksis karena menggunakan bahasa sehari-hari (bahasa inggris). SQL tidak memiliki control flow dan deklarasi variabel seperti halnya bahasa pemrograman. Untuk menangani hal tersebut SQL bisa digabungkan dengan bahasa pemrograman tertentu sehingga bisa lebih dinamis.

Secara umum perintah SQL terbagi 3, yaitu :
  • DDL (Data Defenition Language) Perintah untuk membuat Database baru, dan pemanipulasian objek-objek terkait yang ada dalam database tersebut. Contoh : CREATE TABLE, DROP TABLE, ALTER TABLE 
  • DML (Data Manipulation Language) Berhubungan dengan query dan pemanipulasian table di database. Contoh : SELECT, INSERT, UPDATE, DELETE
  •  DCL (Data Control Language) Perintah yang berhubungan dengan manajemen user. Perintah DCL ini hanya tersedia untuk database bertipe client-server yang penggunanya lebih dari 1 user. Contoh : GRANT, REVOKE 
 Class yang digunakan untuk mengeksekusi perintah SQL adalah OleDbCommand pada MS Access atau SqlCommand pada SQL Server. OleDbCommand dan SqlCommand memiliki parameter constructor perintah sql dan Connection.

Contoh :

Class OleDbCommand memiliki method utama ExecuteNonQuery() dan ExecuteReader() method ExecuteNonQuery() digunakan untuk mengeksekusi perintah SQL manipulasi data seperti INSERT, UPDATE, dan DELETE. Method ExecuteReader() digunakan hanya untuk perintah sql SELECT, return value dari method tersebut adalah objek OleDbDataReader atau SqlDataReader

INSERT

MS Access :


string sql="INSERT INTO Customers (CompanyName,Address) VALUES (" 
                                           + "'XERIS','Sentul Valley')"; 
OleDbCommand cmd=new OleDbCommand(sql,conn);
cmd.ExecuteNonQuery();


atau :


string sql="INSERT INTO Customers (CompanyName, Address) VALUES " 
                                          + "('XERIS','Sentul Valley')"; 
OleDbCommand cmd=new OleDbCommand(); 
cmd.Connection=conn; 
cmd.CommandText=sql; 
cmd.ExecuteNonQuery();

 SQL Server :
 


string sql="INSERT INTO Customers (CompanyName,Address) VALUES "
                                                            + "('XERIS','Sentul Valley')"; 
SqlCommand cmd=new SqlCommand(sql,conn); 
cmd.ExecuteNonQuery();

atau :



string sql="INSERT INTO Customers (CompanyName,Address) VALUES "
                                                            + "('XERIS','Sentul Valley')";
SqlCommand cmd=new SqlCommand();
cmd.Connection=conn;
cmd.CommandText=sql;
cmd.ExecuteNonQuery();

UPDATE

MS Access :



string sql="UPDATE Customers SET CompanyName='XERIS System',Address='BOGOR'"
+ "WHERE CustomerID=1"; 
OleDbCommand cmd=new OleDbCommand(sql,conn);
cmd.ExecuteNonQuery();

SQL Server :


string sql="UPDATE Customers SET CompanyName='XERIS System',Address='JEDAH'" 
+ "WHERE CustomerID=1";
SqlCommand cmd=new SqlCommand(sql,conn); 
cmd.ExecuteNonQuery();

 DELETE

MS ACCESS

string sql="DELETE Customers WHERE CustomerID='XERIS'"; 
OleDbCommand cmd=new OleDbCommand(sql,conn); 
cmd.ExecuteNonQuery();

SQL Server :

string sql="DELETE Customers WHERE CustomerID='XERIS'"; 
SqlCommand cmd=new SqlCommand(sql,conn); 
cmd.ExecuteNonQuery();

3. Menampilkan Data
Untuk menampilkan data di ADO.NET class yang digunakan adalah OleDbDataReader dan SqlDataReader DataReader ini sifatnya forward-only artinya hanya bisa baca maju ke depan, tidak bisa Move previuos atau Move Next seperti pada ADO classic

MS Access

string sql="SELECT * FROM Customers"; 
OleDbCommand cmd=new OleDbCommand(sql,conn);
OleDbDataReader rdr=cmd.ExecuteReader(); 
while (rdr.Read()) 
 {
 Console.WriteLine(Convert.ToInt32(rdr["CustomerID"]));  
  Console.WriteLine(Convert.ToString(rdr["CompanyName"])); 
  } 
rdr.Close(); 
cmd.Dispose();

 SQL Server:

string sql="SELECT * FROM Customers";
SqlCommand cmd=new SqlCommand(sql,conn);
SqlDataReader rdr=cmd.ExecuteReader(); 
while (rdr.Read()) 
  { 
    Console.WriteLine(Convert.ToInt32(rdr["CustomerID"]));    
    Console.WriteLine(Convert.ToString(rdr["CompanyName"])); 
    } 
rdr.Close();
cmd.Dispose();

 Pemanggilan method ExecuteReader() menghasilkan semua record tabel Customers dan disimpan di objek OleDbDataReader/SqlDataReader. Untuk menampilkan record di object tersebut gunakan statement looping while. Jika data tersebut ada maka tampilkan di Console dengan perintah Console.WriteLine(). Convert berfungsi untuk mengubah objek ke tipe yang bersesuaian dengan tipe field di table nya

UNTUK DATASET TUNGGU DI POSTING BERIKUT NYA.


Fungsi IIF

. Sebenarnya fungsi IIF sama dengan fungsi IF biasa, yang sama-sama digunakan untuk memeriksa benar tidaknya (true / false) suatu ekspresi, hanya saja strukturnya lebih sederhana. Jika Anda mempunyai pengalaman dengan aplikasi MS Excel, maka Anda dapat dengan mudah menggunakan fungsi ini, karena struktur fungsi IIF dalam Visual Basic sama persis dengan fungsi IF dalam MS Excel. Berikut strukturnya :

 

IIf ( Ekspresi yang diperiksa, Nilai jika ekspresi True, Nilai jika ekspresi False )

Contoh penggunaanya seperti ini :

b = IIf(a = 1, "Setuju", "Tidak setuju")
Dapat dilihat bahwa ada dua variabel yaitu 'a' dan 'b'. Terjemahan kode diatas adalah Jika variabel 'a' bernilai 1, maka variabel 'b' bernilai "Setuju", dan Jika variabel 'a' tidak bernilai 1, maka variabel 'b' bernilai "Tidak setuju".

Anda juga dapat melakukan pencabangan seperti ini :

b = IIf(a < 2, IIf(a = 1, "Kuda", "Macan"), "Sapi")
Jika 'a' bernilai kurang dari 2, maka :
            (Jika 'a' bernilai 1, maka 'b' bernilai "Kuda", dan Jika tidak maka 'b' bernilai "Macan")
dan Jika 'a' tidak kurang dari 2 maka 'b' bernilai "Sapi".