久仰ORM大名由來已久,但真正學習ORM才是前兩周的事,在網上挑來揀去,終於決定好好學習一下NHibernate(IBatisNet我也比較感興趣,但是鑒於時間有限,暫時擱置),一來因為其鼻祖Hibernate名氣大,二來嘛,因為它是開源的,有機會看看它的源碼,呵呵!
上網搜了好久,沒搜到幾篇文檔,沒法子只能啃Hibernate的文檔慢慢學習了,不久我就發現一個問題:NHibernate好像不能同時操作幾個資料庫嘛?假設有這樣分布式系統,它有N個用戶端,一個應用程式伺服器,多個資料庫伺服器,用戶端可以根據自己的配置通過應用程式伺服器串連到不同的資料庫伺服器(應該就是聽棠描述的所謂多帳套),NHibernate應該如何處理這種情況呢?如果瞭解一點NHibernate的配置的話,大概就知道是通過Configuration.BuildSessionFactory獲得ISessionFactory介面的,而通過這種方法我們只能利用連接字串指定一個預設的資料庫,在《在Window Form中使用NHibernate》一文中提到可以通過增加一個設定檔的方式串連到其它的資料庫,但按照原文的意思,如果要使用第二個資料庫,意味著要第二次進行昂貴的BuildSessionFactory調用,而且假如我們允許使用者建立刪除資料庫的話,設定檔實在是不夠靈活,那麼有什麼辦法可以達到我們的目的呢?
查閱NHibernate的doc,無意中發現OpenSession有個overload的方法,可以提供一個IDbConnection的參數,看來老天有眼,直覺告訴我,就是它了!!!經過實驗,只要指定這個參數,就可以輕輕鬆鬆實現動態改變串連的資料庫了!廢話少說,看代碼……
首先是SessionFactory的代碼,這裡將SessionFactory實現為單例,主要是因為SessionFactory建立極為耗時耗力,這樣可以避免重複建立。
using System;
using System.Reflection;
using System.Diagnostics;
using System.Data;
using NHibernate;
using NHibernate.Cfg;
namespace MyProject.Services
{
public class SessionFactory
{
private static Configuration _configuration = null;
private static ISessionFactory _factory = null;
static SessionFactory()
{
_configuration = new Configuration();
_configuration.SetProperty("hibernate.dialect", "NHibernate.Dialect.MsSql2000Dialect");
_configuration.SetProperty("hibernate.connection.provider",
"NHibernate.Connection.DriverConnectionProvider");
_configuration.SetProperty("hibernate.connection.driver_class",
"NHibernate.Driver.SqlClientDriver");
_configuration.SetProperty("hibernate.connection.connection_string",
@"Server=localhost;initial catalog=master;Integrated Security=SSPI");
_configuration.AddAssembly(Assembly.Load("MyProject.Beans"));
_factory = _configuration.BuildSessionFactory();
}
public static ISession OpenSession()
{
Debug.Assert(_factory != null, "ISessionFactory is null");
return _factory.OpenSession();
}
public static ISession OpenSession(IDbConnection connection)
{
Debug.Assert(_factory != null, "ISessionFactory is null");
Debug.Assert(connection != null, "IDbConnection is null");
return _factory.OpenSession(connection);
}
public static void Initialize()
{
// do nothing, just trigger the static .ctor
}
}
}
大家可以發現,我串連的居然master資料庫,嘿嘿,不錯,這就是奧妙所在了,調用BuildSessionFactory的時候,指定哪個資料庫並沒有太大關係,你可以指定任何一個資料庫都沒有問題,當然,這樣做的後果就是你必須在OpenSession的時候指定一個串連,否則的話,狠狠,後果自負哦!
好了,上面就是全部的關鍵了,接下來就是如何使用的問題了,我這裡舉個例子,以做拋磚引玉之用:
public static void TestAddUser(User newUser)
{
string connstring = @"Server=localhost;initial catalog=gcs2;Integrated Security=SSPI";
using (SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
ISession session = SessionFactory.OpenSession(conn as IDbConnection);
ITransaction transaction = session.BeginTransaction();
try
{
session.Save(newUser);
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw ex;
}
finally
{
session.Close();
}
}
}
相關的調用代碼如下:
private void btnAdd_Click(object sender, EventArgs e)
{
User newUser = new User();
newUser.Name = "<new user>";
newUser.Password = "<none>";
newUser.CreateDate = DateTime.Now;
newUser.LastLogin = DateTime.Now;
UserFactory.TestAddUser(newUser);
}
如果沒有問題的話,最終User將被儲存到gcs2資料庫中,而不是master資料庫!事實上,通過改變TestAddUser成員函數中的連接字串(可以由用戶端傳過來),你說吧,你想連到哪兒?呵呵!
當然大家也看到了,強行指定connection是以犧牲代碼的平台移植性為代價的。我這裡就強行指定了SqlConnection作為實際串連,當然,這個問題很好解決,一個簡單工廠就綽綽有餘了,好,enjoy it!
註:這是本人第一次發表有關NHibernate的文章,而且本人才疏學淺,如有遺漏或錯誤之處,請各位指正!
『the end』