NHibernate In Action

Hibernating with Example

Product Repository Refactoring:NHibernate Helper

dengan 3 komentar

Pada bagian sebelumnya, kita telah belajar bagaimana melakukan operasi CRUD. Kita memanggil operasi CRUD secara eksplisit melalui session. Bagaimana kalau pemanggilan itu kita buat secara implisit. Jadi, operasinya akan terlihat seperti ini

Untuk meyimpan product:

           productRepository.Save(product)

Untuk memanggil kembali product dengan id:

            IProduct product=productRepository.GetById(productId)

atau dengan nama:

IProduct product =productRepository.GetByName("Apple")

Untuk menghapus product:

   productRepository.Remove(product)

Untuk memanggil List Product berdasarkan kategori:

IList products=productRepository.GetByCategory("Fruits")

Jadi, kita membutuhkan object ProductRepository yang didalamnya terdapat NHibernateHelper. NHibernateHelper memiliki method OpenSession.

NHibernate Helper

Pertama sekali kita buat class test baru

[TestFixture]
public class NHibernateHelperFixture
{
    [Test]
    public void OpenSessionTest() {
      INHibernateHelper nhHelper=new NHibernateHelper();
      ISession session=nhHelper.OpenSession();
      Assert.IsNotNull(session);
    }
}

Buat project baru untuk repository, katakanlah bernama: fatur.sample.NHibernateHelloWorld.Repository. Jika project dibuat dengan IDE dan monodevelop , biasanya sudah ada file AssemblyInfo.cs didalamnya. Karena target build untuk app, dalam project nant, membuat semua code didalam folder app menjadi 1 assembly, maka AssemblyInfo.cs tidak boleh lebih dari satu. So, kita harus mengeluarkannya dari daftar yang akan dicompile. Gunakan element exclude untuk mengeluarkan file dari daftar.

Buat interface INHibernateHelper di project Repository.

 namespace fatur.sample.NHibernateHelloWorld.Repository
{
  public interface INHibernateHelper
  {
    ISession OpenSession();
  }
}

Buat class NHibernateHelper yang mengimplementasikan interface diatas.

namespace fatur.sample.NHibernateHelloWorld.Repository
{
   public class NHibernateHelper:INHibernateHelper
   {
    public NHibernateHelper()
     {
     }
    public ISession OpenSession()
     {
      return null;
     }
  }
}

Untuk sementara saya biarkan me-return null.

Agar bisa dicompile kita harus menambahkan reference NHibernate kedalam reference.

Sampai disini nunit mengatakan error karena null. OK, memang itu yang kita harapkan. Kita coba implemantasi langsung saja. Saya akan copikan apa yang ada didalam SetupFixture sebelumnya,

public class NHibernateHelper:INHibernateHelper
{
   private ISessionFactory _sessionFactory;
   private Configuration _configuration;
   public NHibernateHelper()
     {
        _configuration = new Configuration();
        _configuration.Configure();
        _configuration.AddAssembly(typeof (Product).Assembly);
        _configuration.AddXmlFile("Product.hbm.xml");
        _sessionFactory = _configuration.BuildSessionFactory();
      }

   public ISession OpenSession()
      {
        return _sessionFactory.OpenSession();
      }
}

Jalankan test, dan seharusnya sukses.

Create database Menggunakan Schema

Kita juga harus membuat helper bisa membantu men-generate database. Kita buat teest untuk export schema. Disini method saya beri nama “CreateDatabase” agar lebih bermakna sesuai konteks.

[Test]
public void SchemaExport()
{
   INHibernateHelper nhHelper=new NHibernateHelper();
   nhHelper.CreateDatabase();
}

Untuk memenuhi test ini, kita tambahkan method CreateDatabase didalam interface

 public interface INHibernateHelper
      {
          ISession OpenSession();
          void CreateDatabase();
       }

dan implementasinya di class NHibernateHelper,

public class NHibernateHelper:INHibernateHelper
{
      private ISessionFactory _sessionFactory;
      private Configuration _configuration;
      ...
      public void CreateDatabase()
        {

        }
}

Sementara kita biarkan tanpa ada implementasi apapun. Jalankan test, pastikan tidak ada error.

Sekarang kita buat implementasinya. Saya kopikan saja schema export dari test sebelumnya.

public class NHibernateHelper:INHibernateHelper
{
     private ISessionFactory _sessionFactory;
     private Configuration _configuration;

     ...

      public void CreateDatabase()
     {
         new SchemaExport(_configuration).Execute(false, true, false, false);
      }
 }

Test saya jalankan. Tidak ada masalah. Good.

Repository Test Refactoring

Kembali ke class ProductRepositoryFixture. Saya tambahkan helper ke dalam class

 [TestFixture]
 public class ProductRepositoryFixture
 {
     private ISessionFactory _sessionFactory;
     private Configuration _configuration;
     private INHibernateHelper _hibernateHelper;

     [TestFixtureSetUp]
     public void TestFixtureSetUp()
      {
        _configuration = new Configuration();
        _configuration.Configure();
        _configuration.AddAssembly(typeof (Product).Assembly);
        _configuration.AddXmlFile("Product.hbm.xml");
        _sessionFactory = _configuration.BuildSessionFactory();
        _hibernateHelper=new NHibernateHelper();
      }
}

Test saya jalankan. No problem.

Next. Kita coba yang pertama, schemaexport saya ganti menjadi

 [SetUp]
 public void SetupContext()
{
     _hibernateHelper.CreateDatabase();
}

Test saya jalankan. Sukses.

Add product

Sekarang kita coba untuk insert product. Hah, kita belum punya class repository. Ok. kita buat dulu. Untuk membuatnya kita mulai dari test. Saya remark sebagian test sebelumnya dan saya ganti dengan definsisi baru:

[Test]
public void Can_add_new_product()
{
     var product= new Product {Name = "Apple", Category = "Fruits"};
      IProductRepository productRepo=new   ProductRepository(_hibernateHelper);
      productRepo.Add(product);

      /* using (ISession session = _sessionFactory.OpenSession())
         using (ITransaction transaction = session.BeginTransaction())
          {
             session.Save(product);
             transaction.Commit();
          }
      */
}

Dari implementasi baru diatas, kita belum memiliki IProductRepository dan ProductRepository. Tambahkan class baru di project repository interface dan class berikut ini:

Interface

namespace fatur.sample.NHibernateHelloWorld.Repository
{
   public interface IProductRepository
   {
      void Add(IProduct product);
    }
}

Class

namespace fatur.sample.NHibernateHelloWorld.Repository
{
    public class ProductRepository:IProductRepository
   {
      private INHibernateHelper _nhHelper;
      public ProductRepository(INHibernateHelper nhHelper)
      {
         this._nhHelper =nhHelper;
      }
       public void Add(IProduct product){

      }
  }
}

Lagi, implementasi Add saya biarkan kosong. Semua test yang memanggil add product error. Tidak apa-apa, karena memang belum kita implementasikan.

Untuk implemantasinya, saya kopikan saja code yang saya remark ke dalam method Add.

public void Add(IProduct product)
{
    using (ISession session = _nhHelper.OpenSession())
    using (ITransaction transaction = session.BeginTransaction())
    {
       session.Save(product);
       transaction.Commit();
    }
}

Test saya jalankan dan sukses. Bagian test yang saya remark, saya hapus.

Langkah diatas saya ulang-ulang untuk operasi lainnya. Hasilnya,

Class Test

[TestFixture]
public class ProductRepositoryFixture
{
    private INHibernateHelper _hibernateHelper;
    [TestFixtureSetUp]
    public void TestFixtureSetUp()
    {
      _hibernateHelper=new NHibernateHelper();
    }
    [SetUp]
    public void SetupContext()
    {
     _hibernateHelper.CreateDatabase();
    }

    [Test]
    public void Can_add_new_product()
    {
      var product= new Product {Name = "Apple", Category =   "Fruits"};
      IProductRepository productRepo=new ProductRepository(_hibernateHelper);
      productRepo.Add(product);
    }

    [Test]
    public void Can_get_product()
    {
      IProduct product;
      this.Can_add_new_product();
      product=getProduct();
      Assert.AreEqual("Apple",product.Name);
     }

     private IProduct getProduct()
     {
        IProductRepository productRepo= new ProductRepository(_hibernateHelper);
        return productRepo.GetById(1L);
     }

     [Test]
     public void Can_update_existing_product()
     {
         this.Can_add_new_product();
         IProduct product=this.getProduct();
         product.Name="Semangka";
         IProductRepository productRepo=new ProductRepository(_hibernateHelper);
         productRepo.Update(product);
         IProduct reloadProduct=this.getProduct();
         Assert.AreEqual("Semangka",reloadProduct.Name);
      }

     [Test]
     public void Can_remove_existing_product()
     {
         this.Can_add_new_product();
         IProduct product=this.getProduct();
         IProductRepository productRepo=new ProductRepository(_hibernateHelper);
         productRepo.Remove(product);
         var fromDb=this.getProduct();
         Assert.IsNull(fromDb);
      }

      [Test]
      public void Can_get_existing_product_by_name()
      {
          this.Can_add_new_product();
          IProductRepository productRepo= new ProductRepository(_hibernateHelper);
          IProduct product=productRepo.GetByName("Apple");
          Assert.AreEqual("Apple",product.Name);
       }

       [Test]
       public void Can_get_existing_products_by_category()
       {
	   this.addProducts();
	   IProductRepository productRepo= new ProductRepository(_hibernateHelper);
	   ICollection products = productRepo.GetByCategory("Fruits");
	   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"};
             IProductRepository productRepo= new  ProductRepository(_hibernateHelper);
	     productRepo.Add(apple);
	     productRepo.Add(durian);
	     productRepo.Add(tomato);
	}

}

Class ProductRepository

public class ProductRepository:IProductRepository
{
	private INHibernateHelper _nhHelper;
	public ProductRepository(INHibernateHelper nhHelper)
	{
		this._nhHelper =nhHelper;
	}
	public void Add(IProduct product){
		using (ISession session = _nhHelper.OpenSession())
		using (ITransaction transaction = session.BeginTransaction())
		{
			session.Save(product);
			transaction.Commit();
		}
	}

	public IProduct GetById(long id){
		using (ISession session = _nhHelper.OpenSession())
		return session.Get(1L);
	}

	public void Update(IProduct product){
		using (ISession session =  _nhHelper.OpenSession())
		using (ITransaction transaction = session.BeginTransaction())
		{
			session.Update(product);
			transaction.Commit();
		}
    }

	public void Remove(IProduct product){
		using (ISession session = _nhHelper.OpenSession())
		using (ITransaction transaction = session.BeginTransaction())
		{
			session.Delete(product);
			transaction.Commit();
		}
	}

	public IProduct GetByName(string name){
		using (ISession session=_nhHelper.OpenSession())
		{
		return session.CreateQuery("from Product p where p.Name=:name").SetString("name", "Apple").UniqueResult();
		}
	}

	public ICollection GetByCategory(string name){
	using (ISession session = _nhHelper.OpenSession())
		{
		return session.CreateCriteria(typeof(IProduct))
		.Add(Restrictions.Eq("Category", "Fruits")).List();
		}
	}

}

Dan interface

public interface IProductRepository
{
	void Add(IProduct product);
	IProduct GetById(long id);
	IProduct GetByName(string name);
	void Update(IProduct product);
	void Remove(IProduct product);
	ICollection GetByCategory(string name);
}

What Next

Cara diatas sudah saya pakai beberapa kali untuk production, tetapi masih skala kecil. Ketika software skalanya membesar, kita harus berhati-hati menghandle Session Factory. Karena itu daripada menggunakan helper seperti diatas saya lebih memilih menggunakan Spring.Net yang didalamnya terdapat HibernateTemplate support–yang pada dasarnya sama dengan helper yang kita buat, tetapi dengan fasilitas yang lebih lengkap.

Berikutnya kita akan belajar mengenai collection, proxy dan lazy loading.

Ditulis oleh h4kun4m4t4t4

Februari 9, 2009 pada 3:40 am

Ditulis dalam Uncategorized

3 Tanggapan

Berlangganan komentar dengan RSS.

  1. thanks for sharing kaka..
    sayang gak nulis lagi..
    smoga bisa dilanjut lagi :P

    regards

    Mochamad Fazar

    September 30, 2010 pada 11:12 am

    • yang kek gitu dah gak jaman lagi zar, semua dah ada di spring.net HibernateTemplate.
      dan kalau fazar ngerti CQRS, kita hanya butuh session doang disisi command.

      mfathur

      Oktober 1, 2010 pada 7:11 am

      • waduh belum ngerti CQRS nih,,
        berarti kalo jaman sekarang bisa langsung pake library nya HibernateTemplate itu y..
        sekalian aja kaka fathur nulis teknologi baru lagi :P ,,lumayan newbie kayak saya jadi terbantu :D

        Mochamad Fazar

        Oktober 1, 2010 pada 10:14 am


Tinggalkan Balasan

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Ubah )

Twitter picture

You are commenting using your Twitter account. Log Out / Ubah )

Facebook photo

You are commenting using your Facebook account. Log Out / Ubah )

Connecting to %s

Ikuti

Get every new post delivered to your Inbox.