IronPython ActiveRecord In Action: 如此简单
ROR ActiveRecord从概念上来说是目前最为理想的ORM,因为只要按照默认的规则,它完全不需要程序员维护任何实体属性和映射文件,这是动态语言强大的运行期特性的体现。但是在.Net平台上,IronRuby目前还远远没有达到可用的地步。那么用比较成熟的IronPython能否达到类似的效果呢?我做了个实验,结果发现确实是可行的。更加美妙的是,动态构造的属性不但能够在Python代码中直接使用,而且也能够通过反射获取,从而映射到ASP.NET页面也不需要任何额外的工作。
下面就是例子。我们可以在页面的Code Behind代码中访问python代码:
{
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脚本如下:
@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都对多种主流动态语言提供了相当完整的支援,这种情况什么时候才能改变呢?