CRUD Operation menggunakan NHibernate
Pada tulisan saya sebelumnya, Mengkonfigurasi NHibernate, saya telah paparkan bagaimana mengkonfigurasi NHibernate dan sedikit mapping. Tulisan ini merupakan lanjutan dari tulisan sebelumnya.
Konfigurasi Test Repository
Mengacu pada Domain Driven Design (DDD), Repository adalah entry point untuk mengakses data. Lewat repository-lah data dimasukkan, dipanggil kembali, diupdate dan dihapus.
Karena test kita kali ini menyentuh inftastuktur (database), kita harus membuat sedemikian hingga diawal dan diakhir test kondisi infrastruktur tidak boleh berubah. Sehingga test satu tidak mempengaruhi test yang lainnya.
Pada saat dijalankan kondisi database adalah hanya berisi tabel product yang kosong. Dalam contoh ini, saya hanya akan memenuhi kondisi: diawal setiap setiap test tersedia tabel product yang kosong. Karena itu saya membuat siklus test seperti berikut ini:
[TestFixture]
public class ProductRepositoryFixture
{
private ISessionFactory _sessionFactory;
private Configuration _configuration;
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
_configuration = new Configuration();
_configuration.Configure();
_configuration.AddAssembly(typeof (Product).Assembly);
_configuration.AddXmlFile("Product.hbm.xml");
_sessionFactory = _configuration.BuildSessionFactory();
}
[SetUp]
public void SetupContext()
{
new SchemaExport(_configuration).Execute(false, true,false, false);
}
}
Jadi buatlah file test baru, ProductRepositoryFixture.cs, dalam project test anda. SessionFactory adalah object yang sangat berat inisiasinya, karena disitulah semua mapping diterjemahkan dan disimpan. Jadi ide-nya harus singleton, dibuat sekali dan dipakai bersama-sama oleh keseluruhan test. Atribute [TestFixtureSetup] memastikan bahwa method TestFixtureSetup hanya dijalankan sekali, yaitu pada saat object dibuat.
Kemudian, karena kita mengharapkan setiap kali test hendak dijalankan tabel product adalah baru dibuat, maka kita gunakan attribute [SetUp]. Attribute ini akan memastikan kalau method SetupContext dijalankan setiap kali test akan dijalankan. ExportSchema akan menghapus tabel product dan membuat tabel yang baru.
Insert Product
Untuk membuat dan memasukkan product baru ke dalam database, kita buat test berikut ini:
[Test]
public void Can_add_new_product()
{
var product= new Product {Name = "Apple", Category = "Fruits"};
using (ISession session = _sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(product);
transaction.Commit();
}
}
Jadi, kita buat sesi baru dengan memanggil method OpenSession() dari
SessionFactory. Dari session yang telah kita dapatkan itu kita buat
transaction dengan memanggil BeginTransaction() dari Session.
Untuk menyimpan Product cukup memanggil method Save() dari session.
Untuk menutup transaksi cukup panggil method Commit() dari object
transaction. Kita akan bahas lebih khusus nanti menangani kebijakan
bagaimana menggunakan session dan transaction.
Using kita gunakan untuk memastikan session dan transaction ditutup setelah digunakan.
Jika tidak ada pesan kesalahan, berarti test ini sukses.
Memanggil kembali Product
Berikut ini adalah test untuk mengambil product dari database:
[Test]
public void Can_get_product()
{
IProduct product;
this.Can_add_new_product();
product=getProduct();
Assert.AreEqual("Apple",product.Name);
}
private IProduct getProduct()
{
using (ISession session = _sessionFactory.OpenSession())
return session.Get<Product>(1L);
}
Untuk mengambil data, kita harus membuat session. Product saya ambil
dengan id 1L. Ingat, id kita serahkan ke database untuk dibuat dengan sequence.
Jadi 1L adalah nilai yang pasti untuk product key.
Jika tidak ada pesan kesalahan, product yang keluar harus bernama “Apple”.
Update Product
Untuk melakukan test update product, kita harus panggil product dari database, kita update property-nya, kemudian kita simpan kembali.
[Test]
public void Can_update_existing_produc()
{
this.Can_add_new_product();
IProduct product=this.getProduct();
using (ISession session = sessionFactory.OpenSession())
using (ITransaction transaction= session.BeginTransaction())
{
product.Name="Semangka";
session.Update(product);
transaction.Commit();
}
IProduct reloadProduct=this.getProduct();
Assert.AreEqual("Semangka",reloadProduct.Name);
}
Product kita panggil kembali, kemudian kita ganti namanya dari “Apple” menjadi “Semangka”.
Menghapus Product
Untuk menghapus Product, kita panggil product kemudian kita perintahkan nhibernate untuk menghapus melalui session.
[Test]
public void Can_remove_existing_product()
{
this.Can_add_new_product();
IProduct product=this.getProduct();
using (ISession session = _sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(product);
transaction.Commit();
}
var fromDb=this.getProduct();
Assert.IsNull(fromDb);
}
Memanggil Product dengan HQL
Berikut ini adalah cara bagaimana memanggil product berdasarkan nama. Disini kita menggunkan HQL (hibernate query language). Kita bahas lebih khusus nanti dibagian advance query.
[Test]
public void Can_get_existing_product_by_name(
{
this.Can_add_new_product();
IProduct product;
using (ISession session=_sessionFactory.OpenSession())
{
product = session.CreateQuery("from Product p where p.Name=:name").SetString("name","Apple").UniqueResult<Product>();
}
Assert.AreEqual("Apple",product.Name);
}
Parameter selalu ditandai dengan prefix “:”.
Memanggil Product dengan Creteria
Selain dengan HQL, kita juga bisa membuat query dengan kriteria:
[Test]
public void Can_get_existing_product_by_criteria()
{
this.Can_add_new_product();
IProduct product;
using (ISession session=_sessionFactory.OpenSession())
{
product = session.CreateCriteria(typeof(Pro</span>duct)).Add(Restrictions.Eq("Name</span>", "Apple")).UniqueResult<Product>();
}
Assert.AreEqual("Apple",product.Name);
}
Jangan lupa untuk me-use: NHibernate.Criterion.
Memanggil List Product Berdasarkan Kategori
Test-test sebelumnya kita memanggil object tunggal. Bagaimana cara memanggil product dalam bentuk list? Pertama-tama kita harus tambahkan ke dalam database beberapa product. Kemudian kita panggil product-product itu dengan kriteria:
[Test]
public void Can_get_existing_products_by_category()
{
this.addProducts();
ICollection<Product> products;
using (ISession session =_sessionFactory.OpenSession())
{
products = session.CreateCriteria(typeof(Product).Add(Restrictions.Eq("Cate</span>gory", "Fruits")).List<Product>();
}
Assert.AreEqual(2,products.Count);
}
private void addProducts()
{
var apple= new Product {Name = "Apple", Category = "Fruits"};
var durian=new Product {Name="Durian", Category ="Fruits"};
var tomato=new Product {Name= "Tomato", Category = Vegetable"};
using (ISession session =_sessionFactory.OpenSession())
using (ITransaction transaction =session.BeginTransaction())
{
session.Save(apple);
session.Save(durian);
session.Save(tomato);
transaction.Commit();
}
}
What Next
Kita telah melakukan test CRUD. Berikutnya kita akan pindahkan repository dalam assembly khusus. Kita buat abstraksi disana. Great Refactoring!