[Castle ActiveRecord] 1. Starter

http://www.rainsts.net/default.asp?cat=1

以前研究過一陣 ORM,基於某些理由,比較喜歡 XPO 和 Castle ActiveRecord。原因不外乎以下幾點:

  • "Class to DB",我覺得 ORM 最重要的目的是用一種簡便的方式來存儲對象。我們對業務分析的重點是對象,而不會優先考慮數據庫設計。XPO 和 Castle AR 在這方面做得都很好。
  • 一個是著名廠商 DevExpress 的產品,另一個是被廣泛使用的 NHibernate 的封裝,較好的升級保障對於項目開發是很重要的。網上一些個人的 ORM 作品雖然很有特色,但畢竟沒人能保證 "未來三天" 它是否依然存在,也沒有人能保證 Bug 會得到修復。
  • 這兩個組件都能得到較好的技術支持,XPO 是商業軟件自不必說,NHibernate 的用戶羣組和開發資料網上也很多。
  • 基於開發成本考慮,這兩套組件無論是代碼維護還是人力資源上都有較好的性價比。
  • 最後就是我個人對用於映射的配置文件有那麼點 "偏見"。除非是改造現有系統,否則這些配置文件幾乎不會發生改變。基於特性的映射將數據庫、配置文件、實體類三個變化源歸納到一起,更好維護一些。
最近打算用 ORM 做點東西,細細衡量之下,還是選擇 Castle AR,畢竟 "OpenSource" 的授權方式還是比較吸引人的。看了看以前寫的 AR 文章,有點簡單,有點落後,所以再寫一點,應該沒有炒剩飯的嫌疑。

------------ 以上都是題外話,就此打住!----------------------

AR 中有個類叫 ActiveRecordStarter,它是 AR 運行的起始點。我們就用它拉開序幕,重新研究 Castle AR RC2 的功能和特點。特別申明,我使用的 Castle 版本是從 Build Server 獲取的最新編譯版本 (castleproject-1.1-build_382-net-2.0-debug.zip)。

ActiveRecordStarter 的核心任務是獲取所有 ActiveRecord 實體類型的信息,並創建 ActiveRecordModel。當然,ActiveRecordStarter 作用遠不止如此。

1. 創建數據庫連接

AR 沿用了 NHibernate 的配置習慣,我們可以使用配置文件,也可以使用代碼。雖然我們可以使用默認方式,將配置信息寫入 App.config / web.config,但我建議你使用單獨的配置文件更好維護一些。

ar.xml

<?xml version="1.0" encoding="utf-8" ?>
<activerecord>
    <config>
        <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
        <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
        <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
        <add key="hibernate.connection.connection_string" value="server=(local);uid=sa;pwd=123456;database=test" />
    </config>
</activerecord>

XmlConfigurationSource

XmlConfigurationSource config = new XmlConfigurationSource("ar.xml");
ActiveRecordStarter.Initialize(Assembly.GetCallingAssembly(), config);

當然,我們還可以使用代碼來代替配置文件。(注意添加 Castle.Core.dll 的引用。)
InPlaceConfigurationSource config = new InPlaceConfigurationSource();

Hashtable properties = new Hashtable();
properties.Add("hibernate.connection.driver_class", "NHibernate.Driver.SqlClientDriver");
properties.Add("hibernate.dialect", "NHibernate.Dialect.MsSql2000Dialect");
properties.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("hibernate.connection.connection_string", "server=(local);uid=sa;pwd=123456;database=test");

config.Add(typeof(ActiveRecordBase), properties);

ActiveRecordStarter.Initialize(Assembly.GetCallingAssembly(), config);

2. 初始化實體類

方式1:指定具體實體類型。

ActiveRecordStarter.Initialize(config, typeof(User), typeof(Order));

方法2:指定程序集,初始化程序集中所有實體類型。 (使用重載方法,我們可以指定多個程序集。)

ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), config);

方法3:後續註冊。

ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), config);
ActiveRecordStarter.RegisterTypes(typeof(User));

由於 Initialize 只能執行一次,所以 "後續註冊" 就非常有用了,如果你看過我寫的有關 CodeDom / Emit 方面的文章,就會明白動態構造類型對於 ORM 有些什麼好處。
public static void Initialize(IConfigurationSource source, params Type[] types)
{
    lock (lockConfig)
    {
        if (isInitialized)
        {
            throw new ActiveRecordInitializationException("You can't invoke ActiveRecordStarter.Initialize more than once");
        }
        ...
    }
}

3. 創建數據庫架構

初始化類型之後,我們可以用 ActiveRecordStarter 提供的方法創建所需的實體數據表了。
// 刪除架構
ActiveRecordStarter.DropSchema();

// 創建架構
ActiveRecordStarter.CreateSchema();

// 創建相關 SQL 腳本。
ActiveRecordStarter.GenerateCreationScripts("create.sql");
ActiveRecordStarter.GenerateDropScripts("drop.sql");

最後,我們寫一個完整一些的例子。
[ActiveRecord("Users")]
public class User
{
    private int id;

    [PrimaryKey(Generator=PrimaryKeyType.Identity)]
    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    private string name;

    [Property(Unique=true, NotNull=true)]
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

}

public class ARTester
{
    public static void Test()
    {
        InPlaceConfigurationSource config = new InPlaceConfigurationSource();
        Hashtable properties = new Hashtable();
        properties.Add("hibernate.connection.driver_class", "NHibernate.Driver.SqlClientDriver");
        properties.Add("hibernate.dialect", "NHibernate.Dialect.MsSql2000Dialect");
        properties.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");
        properties.Add("hibernate.connection.connection_string", "server=(local);uid=sa;pwd=123456;database=test");
        config.Add(typeof(ActiveRecordBase), properties);

        ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), config);

        ActiveRecordStarter.DropSchema();
        ActiveRecordStarter.CreateSchema();

        //ActiveRecordStarter.GenerateCreationScripts("create.sql");
        //ActiveRecordStarter.GenerateDropScripts("drop.sql");
    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章