Data Access Object (DAO) adalah sebuah objek yang bertanggung jawab
untuk melakukan segala hal yang berkaitan dengan database, mulai dari
buka koneksi, query sampai manipulasi data.
Umumnya DAO ini berisi operasi CRUD (Create, Retrieve, Update, Delete)
dimana :
Create = Membuat record baru (SQL INSERT)
Retrieve = Membaca data (SQL SELECT)
Update = Update data (SQL Update)
Delete = Menghapus data (SQL Delete)
Untuk menandakan sebuah class adalah layer DAO gunakan akhiran “Dao”
disetiap class yang dibuat (ini sebetulnya bukan keharusan, hanya
kesepakatan saja). Contoh jika class business object nya
Customer maka DAO bernama CustomerDao
Contoh class CustomerDao
using System;
using System.Data;
using System.Data.SqlClient;
namespace DAO
{
public class CustomerDao
{
public void Create(string customerId,string companyName)
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
string sql = "INSERT INTO Customers (CustomerID,CompanyName) VALUES ("
+ "'" + customerId + "','" + companyName + "')";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
public void Read()
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
string sql = "SELECT * FROM Customers";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"]);
Console.WriteLine(rdr["CompanyName"]);
}
}
public void Update(string customerId, string companyName)
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
string sql = "UPDATE Customers SET CompanyName='" + companyName
+ " WHERE CustomerId='" + customerId + "'";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
public void Delete(string customerId)
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
string sql = "DELETE FROM Customers WHERE CustomerId='" + customerId + "'";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
}
}
Kalau kita perhatikan ada beberapa bagian kode yang dipanggil berulang-
ulang.Setiap method (Create,Retrieve,Update,Delete) ada bagian untuk
buka koneksi, tentu saja hal ini tidak efesien karena salah satu tujun OOP
adalah reusability, penggunaan ulang kembali.
Mengikuti nasihat Martin Fowler, ketika menemukan ada blok kode yg berulang
3 kali maka harus di refactoring. Refactoring adalah pengubuhan struktur kode
tanpa menambah fungsionalitas tertentu. Pengubahan hanya bertujuan untuk
efesiensi danvefektifitas penulisan kode dengan cara menghilangkan atau
menata kembali duplikasi kode yang mungkin terjadi. Ingat bagi programmer
berpengalaman kode yang ditulis tidak hanya harus menyelesaikan masalah
(solve the problem) namun penyelesaian tersebut haruslah indah (elegant)
Bagi saya blok kode tersebut seperti bait-bait puisi, yang ketika membaca
nya saja sudah dapat menggugah perasaan yang paling dalam karena nilai
estetikanya (suit..suit..)
Struktur kode yang bagus juga menyebabkan kode menjadi mudah dibaca .
Tentu saja halini sangat bermanfaat untuk maintenence dikemudian hari,
terlebih lagi jika kita bekerja dalam tim.
Refactoring 1
using System;
using System.Data;
using System.Data.SqlClient;
namespace DAO
{
public class CustomerDao
{
private SqlConnection conn;
public CustomerDao
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
conn = new SqlConnection(connStr);
conn.Open();
}
public void Create(string customerId,string companyName)
{
string sql = "INSERT INTO Customers (CustomerID,CompanyName) VALUES ("
+ "'" + customerId + "','" + companyName + "')";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
public void Read()
{
string sql = "SELECT * FROM Customers";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"]);
Console.WriteLine(rdr["CompanyName"]);
}
}
public void Update(string customerId, string companyName)
{
string sql = "UPDATE Customers SET CompanyName='" + companyName
+ " WHERE CustomerId='" + customerId + "'";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
public void Delete(string customerId)
{
string sql = "DELETE FROM Customers WHERE CustomerId='" + customerId + "'";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
}
}
Kali ini koneksi cukup kita tuliskan sekali pada cosntructor class CustomerDao
deklarasi variabel conn dikeluarkan dari method menjadi field dari class
CustomerDao. Dengan demikian variabel conn dapat diakses diseluruh method
yang dideklarasikan pada class customerDao. Duplikasi kode sudah
dihilangkan, Kali ini kode kita jauh lebih ringkas bukan
Karena kode untuk buka koneksi diletakkan di constructor, maka koneksi ke
database akan dibuka otomatis ketika class CustomerDao di instantiasi
Berikutnya coba perhatikan method Read(), isi dari object rdr langusng
ditampilkan ke console dengan menggunakan perintah Console.WriteLine().
Hmm..lalu dimana permasalahannya?apakah perlu di refactoring juga?
Jawabnya ya. Desain class yang baik harus meminimalisir ketergantungan
antar class. Usahakan class-class yang saling berhubungan bersifat
lousley couple. Perintah Console.Writeline() pada class CustomerDao jelas-
jelas membuat class tersebut tergantung dengan user interface (dalam hal
ini user interface nya berbasis Console)
Bagaimana suatu saat jika user interface nya diganti dengan GUI atau web,
tentu harus kita lakukan perubahan lagi.
Dalam Object Oriented Design dikenal prinsip “separation of concern” atau
ada juga konsep “Single Responsibility Principle”. Salah satu penerapan kedua
konsep ini adalah teknik layering yang sedang kita bahas. masing-masing
layer memiliki tanggung jawab yang unik (single responsibility) yang memiliki
concern tertentu yang spesifik.
Dalam hal ini Data Access Object hanya memiliki concern dan tanggung
jawab terhadap pengaksesan data, tidak ada hubungannya dengan
menampilkan ke layar. Tanggung jawab tersebut (menampilkan ke layar)
diserahkan pada objek di layer Presentation/User Interface
Refactoring 2
public SqlDataReader Read()
{
string sql = "SELECT * FROM Customers";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
return rdr;
}
Cara Mengakses CustomerDao
Layer Presentation :
CustomerDao custDao = new CustomerDao();
SqlDataReader rdr=custDao.Read();
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"]);
Console.WriteLine(rdr["CompanyName"]);
}
That’s it. apakah ada yang perlu diperbaiki lagi?
sepertinya sudah perfect?
Hmm..no code perfect, jangan berpuas diri dulu. Coba sekarang buat lagi
sebuah Data Access Object, namakan saja SupplierDao
using System;
using System.Data;
using System.Data.SqlClient;
namespace DAO
{
public class SupplierDao
{
private SqlConnection conn;
public SupplierDao
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
conn = new SqlConnection(connStr);
conn.Open();
}
public void Create()
{
....
}
public SqlDataReader Read()
{
.....
}
public void Update()
{
........
}
public void Delete()
{
.........
}
}
}
Disetiap constructor Data Access Object ada bagian yang sama, yaitu kode
untuk buka koneksi yang berisi connection string dan object SqlConnection.
Ini juga duplikasi kode tapi letaknya sudah antar class. Bayangkan kalau kita
punya banyak DAO seperti ini, waktu terbuang percuma untuk menulis hal
yang sama, belum lagi kalo connection string nya di edit.Misalnya letak
atau nama database nya diganti. hmmm..welcome to the hell gentlemen
Kalau kita menuruti nasihat Martin Fowler, maka blok kode seperti ini akan
di refactor menjadi class, “Extract method to class”. Buat sendiri class
untuk menagani buka koneksi yang kemudian dipanggil disetiap DAO
public class ConnectionService
{
public static SqlConnection GetConnection()
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
return conn;
}
}
CustomerDao
public class CustomerDao
{
private SqlConnection conn;
public CustomerDao
{
this.conn=ConnectionService.GetConnection();
}
}
SupplierDao
public class SupplierDao
{
private SqlConnection conn;
public SupplierDao
{
this.conn=ConnectionService.GetConnection();
}
}
Sentuhan terakhir tembahkan blok try..catch disetiap method untuk
exception handling (penanganan kesalahan)
Source Code Lengkap :
CustomerDao
using System;
using System.Data;
using System.Data.SqlClient;
namespace DAO
{
public class CustomerDao
{
private SqlConnection conn;
public CustomerDao()
{
this.conn = ConnectionService.GetConnection();
}
public void Create(string customerId, string companyName)
{
try
{
string sql = "INSERT INTO Customers (CustomerID,CompanyName) VALUES ("
+ "'" + customerId + "','" + companyName + "')";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (SqlException sqlex)
{
throw new Exception(sqlex.Message.ToString());
}
}
public SqlDataReader Read()
{
SqlDataReader rdr = null;
try
{
string sql = "SELECT * FROM Customers";
SqlCommand cmd = new SqlCommand(sql, conn);
rdr = cmd.ExecuteReader();
}
catch (SqlException sqlex)
{
throw new Exception(sqlex.Message.ToString());
}
return rdr;
}
public void Update(string customerId, string companyName)
{
string sql = "UPDATE Customers SET CompanyName='" + companyName
+ " WHERE CustomerId='" + customerId + "'";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
public void Delete(string customerId)
{
try
{
string sql = "DELETE FROM Customers WHERE CustomerId='" + customerId + "'";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (SqlException sqlex)
{
throw new Exception(sqlex.Message.ToString());
}
}
}
}
ConnectionService
using System;
using System.Data;
using System.Data.SqlClient;
namespace DAO
{
public class ConnectionService
{
public static SqlConnection GetConnection()
{
SqlConnection conn = null;
try
{
string connStr = "Data Source=SYSTEMINTERFACE\\SQLEXPRESS;"
+ "Initial Catalog=NWIND;Integrated Security=true";
conn = new SqlConnection(connStr);
conn.Open();
}
catch (SqlException sqlex)
{
throw new Exception(sqlex.Message.ToString());
}
return conn;
}
}
}
Main
using System;
using System.Data;
using System.Data.SqlClient;
namespace DAO
{
class Program
{
static void Main(string[] args)
{
CustomerDao custDao = new CustomerDao();
SqlDataReader rdr=custDao.Read();
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"]);
Console.WriteLine(rdr["CompanyName"]);
}
Console.ReadLine();
}
}
}