Shuhari

IronPython ActiveRecord In Action: 如此简单

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都对多种主流动态语言提供了相当完整的支援,这种情况什么时候才能改变呢?

 

posted on 2009-06-17 16:57  Shuhari  阅读(2393)  评论(8编辑  收藏  举报

导航