Castle Active Record : Intro

13 Apr 2008

ไม่ต้องเสียเวลาโม้มาก สั้นๆ ง่ายๆเลยแล้วกัน

Castle LogoCastle ActiveRecord เป็นโปรแกรมที่(ลอก)ได้แรงบันดาลใจมาจาก Active Record ที่ใช้ใน Ruby On Rails ซึ่งเอาแนวคิดมาจาก Martin Fowler อีกที จุดมุ่งหมายคือต้องการสร้าง O/R mapper ที่ใช้งานได้ง่ายให้กับ MonoRails ที่เป็นโคลนของ RoR บน .NET ตัว ActiveRecord เองจริงๆแล้วก็สร้างขึ้นมาบน NHibernate อีกที ถึงแม้ว่า ActiveRecord จะถูกสร้างขึ้นมาสำหรับ MonoRails แล้ว แต่เราก็ดึงเอาแค่ ActiveRecord ออกมาใช้งานเฉยๆก็ย่อมได้เช่นกัน

กลไกการทำงานทั่วๆไปของ ActiveRecord ก็คือจะแทน 1 คลาส = 1 ตาราง และให้แต่ละอ็อปเจกต์แทนแถวของตาราง โดยจะใช้การประกาศแอทริบิวต์แทนการสร้าง Mapping File ของ NHibernate

จากตัวอย่างการประกาศคลาส User
using System;
using Castle.ActiveRecord;

[ActiveRecord]
public class User : ActiveRecordValidationBase<User>
{
    [PrimaryKey(PrimaryKeyType.Native)]
    public virtual int ID { get; set; }

    [Property]
    public virtual string Email { get; set; }

    [Property]
    public virtual string Password { get; set; }
}

เริ่มมาก็ทำการประกาศคลาส User โดย inherit จาก ActiveRecordValidationBase เพื่อนำไปใช้ตอนทำ Validation ตอนหลัง แต่ถ้าหากไม่ทำ Validation เราจะ inherit จาก ActiveRecordBaseแทนก็ได้ แล้วก็สุดท้ายต้องอย่าลืมกำหนด Attribute ActiveRecord ไว้เพื่อบอกว่าคลาสนี้จะทำหน้าที่เป็น Active Record

ในการแทนฟิลด์แต่ละฟิลด์จะใช้ Property ซึ่งในเอกสารบอกว่าควรจะทำเป็น Virtual Property ไว้จะดีกว่าเพราะจะสนับสนุนการทำ Lazy Loading ให้ในตัว แล้วก็ต้องไม่ลืมกำหนดแอททริบิวต์ Property ด้วย

ทีนี้ในการใช้งานเราก็จะต้องบอกว่าให้ไปใช้ฐานข้อมูลไหน ในที่นี้ขอยกตัวอย่างเป็นเว็บแอพพลิเคชัน ก็จะไปตั้งค่าที่ web.config แล้วเพิ่ม section นี้เข้าไปใน element config section

  <configSections>
    <section name="activerecord" type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord"/>
  </configSections>

จากนั้นก็ใส่ element activerecord ลงไปเพื่อกำหนด connection และค่าต่างๆ จากตัวอย่างคือนำไปใช้กับ MySQL แต่ถ้าหากอยากใช้กับฐานข้อมูลอื่นๆ ให้ดูจากหน้า การใช้งาน NHibernate กับฐานข้อมูลอื่นๆ

  <activerecord>
    <config>
      <add
    key="hibernate.connection.driver_class"
    value="NHibernate.Driver.MySqlDataDriver" />
      <add
    key="hibernate.dialect"
    value="NHibernate.Dialect.MySQLDialect" />
      <add
    key="hibernate.connection.provider"
    value="NHibernate.Connection.DriverConnectionProvider" />
      <add
    key="hibernate.connection.connection_string"
    value="Database=ar;Data Source=localhost;User Id=root;Password=mysql" />
    </config>

  </activerecord>

ทีนี้เวลาใช้งาน ก็จะต้องมีการเรียก Active Record เพื่อเริ่มทำงาน ตรงนี้ผมใช้วิธีการสร้างเป็นคลาสที่ inherit มาจากคลาส HttpApplication ขึ้นมาอีกคลาส เมื่อแอพพลิเคชันเร่ิมทำงานให้เริ่มการทำงานของ ActiveRecord ด้วยโดยใช้ค่าต่างๆจาก web.config ที่ตั้งค่าไว้เมื่อกี้ แล้วให้สร้าง Session Scope ของ ActiveRecord ขึ้นมาตอนเริ่ม Request และทำลายทิ้งเมื่อจบ Request

using System;
using System.Web;
using System.Web.Security;
using System.Web.Configuration;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord;


public class GlobalApplication : HttpApplication
{

    private const string STR_Arsessionscope = "ar.sessionscope";
    public GlobalApplication()
    {
        this.BeginRequest += new EventHandler(GlobalApplication_BeginRequest);
        this.EndRequest += new EventHandler(GlobalApplication_EndRequest);

    }

    void GlobalApplication_EndRequest(object sender, EventArgs e)
    {
        try
        {
            SessionScope scope = HttpContext.Current.Items[STR_Arsessionscope] as SessionScope;
            if (scope != null)
            {
                scope.Dispose();
            }
        }
        catch (Exception ex)
        {
            HttpContext.Current.Trace.Warn("Error", "EndRequest: " + ex.Message, ex);
        }
    }

    void GlobalApplication_BeginRequest(object sender, EventArgs e)
    {
        HttpContext.Current.Items.Add(STR_Arsessionscope, new SessionScope());

    }

    public void Application_Start()
    {
        IConfigurationSource source =
            WebConfigurationManager.GetSection("activerecord") as IConfigurationSource;

        InitActiveRecord(source);
    }

    public static void InitActiveRecord(IConfigurationSource source)
    {
        ActiveRecordStarter.Initialize(source,
            typeof(User)

            )
            ;
    }
}

ตรงนี้จะใช้ความถึกเล็กน้อยคือจะต้องบอกตัว ActiveRecordStarter ให้หมดว่าเราจะให้คลาสไหนบ้างที่ทำหน้าที่เป็น ActiveRecord

เสร็จแล้วถ้าเรารันตอนนี้เลยก็ยังใช้งานไม่ได้ จะต้องวิ่งไปบอก Global.asax ให้มา inherit จากคลาสนี้แทนก่อน หลังจากเพิ่ม Global.asax เข้าใน project แล้วก็เปิดแก้ตรงด้านบนเป็น

<%@ Application Language="C#" Inherits="GlobalApplication" %>

ทีนี้ก็ลองสร้าง web form ขึ้นมาทดสอบดู

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
        DataSourceID="ObjectDataSource1">
        <Columns>
            <asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" />
            <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
            <asp:BoundField DataField="Password" HeaderText="Password" 
                SortExpression="Password" />
        </Columns>
    </asp:GridView>


<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
    SelectMethod="FindAll" TypeName="User"></asp:ObjectDataSource>

จากข้อมูลที่มีแบบนี้

db

ก็เอามาแสดงเป็นแบบนี้ได้

db2

เป็นอันว่าสำหรับไปหนึ่งขั้น เจอกันใหม่ตอนหน้า

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.