ROR ActiveRecord從概念上來說是目前最為理想的ORM,因為只要按照預設的規則,它完全不需要程式員維護任何實體屬性和對應檔,這是動態語言強大的運行期特性的體現。但是在.Net平台上,IronRuby目前還遠遠沒有達到可用的地步。那麼用比較成熟的IronPython能否達到類似的效果呢?我做了個實驗,結果發現確實是可行的。更加美妙的是,動態構造的屬性不但能夠在Python代碼中直接使用,而且也能夠通過反射擷取,從而映射到ASP.NET頁面也不需要任何額外的工作。
下面就是例子。我們可以在頁面的Code Behind代碼中訪問python代碼:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
grid.DataSource = RunPythonFunction("User", "query");
grid2.DataSource = RunPythonFunction("Corp", "query");
DataBind();
}
}
private object RunPythonFunction(string className, string funcName)
{
if (_engine == null)
_engine = Python.CreateEngine();
if (_code == null)
{
string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "db.py");
var source = _engine.CreateScriptSourceFromFile(fileName, Encoding.Default, SourceCodeKind.Statements);
_code = source.Compile();
}
var scope = _engine.CreateScope();
_code.Execute(scope);
var klass = scope.GetVariable(className);
var func = _engine.Operations.GetMember<Func<object>>(klass, funcName);
return func();
}
對應的 IronPython指令碼如下:
class ActiveRecord(object):
@classmethod
def getTableName(cls):
return cls.__name__ + 's'
@classmethod
def query(cls):
sql = 'select * from %s' % cls.getTableName()
result = []
conn = SqlConnection(connStr)
try:
conn.Open()
cmd = SqlCommand(sql, conn)
reader = cmd.ExecuteReader()
fields = [reader.GetName(i) for i in range(reader.FieldCount)]
while reader.Read():
record = cls()
for index, field in enumerate(fields):
setattr(record, field, reader[index])
result.append(record)
reader.Close()
cmd.Dispose()
return result
finally:
conn.Close()
class User(ActiveRecord):
pass
class Corp(ActiveRecord):
pass
這麼簡單的幾行代碼就完成了從資料庫記錄到實體的映射。子類不再需要什麼設定檔,資料庫有哪些欄位,實體就自動產生了哪些屬性。
query()方法返回的是一個集合類型,設定到GridView.DataSource就可以直接映射到頁面控制項,和C#手工編寫實體效果完全一樣:
後記:我自己曾經用幾千行C#代碼實現了一個基本的ORM架構,但是現在,我發現同樣的功能用Python只要幾百行代碼就能實現,而且用起來更加簡單。這實在是很讓我有一種把以前的代碼全部扔掉,用IronPython重寫的衝動。唯一不爽的地方是Visual Studio不允許我用Python來寫ASP頁面(IronPython for ASP.NET那個CTP一點也不好用),因此還是不得不寫很多stub代碼在C#和Python之間來迴轉換。雖然微軟聲稱自己在DLR平台的發展上超過Java,但是這未免有點口惠而實不至的味道,因為IDE基本上沒有任何支援。而Java世界不論Eclipse還是Netbeans都對多種主流動態語言提供了相當完整的支援,這種情況什麼時候才能改變呢?