LightSpeed——针对.NET的商业化ORM
LightSpeed是 一种针对.NET的商业化ORM,它拥有多种特性,像实体序列化、健壮的VS设计器、内建的LINQ支持、对DTO的支持等等。我们联系了 Mindscape(开发LightSpeed的公司)的共同创始人John-Daniel Trask,对产品进行了深入探讨,并在总体上对ORM进行了讨论。
InfoQ:现在已经有了很多种开源或者商业化的针对.NET的ORM产品,你为何决定要创建一种新的产品呢?
JD:LightSpeed是Mindscape的第一款产品,我们是基于之 前在IT服务领域的经验来创建的。我们使用过现存的对象-关系映射器(ORM),但是那时在.NET领域并没有太多选择。要么使用NHibernate, 要么就从头创建自己的工具,而很多组织都构建了自己的ORM。我们觉得现存的ORM在性能上和使用的体验上都不是很好,同时也相信业务部门会乐于为优良 的、易于学习、高性能的ORM付费,相对于其它产品或者DIY的方法来说,那会节省他们很多的时间。
InfoQ:你认为ORM应该处理的关键问题有哪些?
JD:ORM的基本目的就在于为数据库和对象世界提供良好的映射关系,所以当然需要把这一点做好。
除 此之外,性能非常重要。最常见的抱怨就是ORM的性能不好,尽管我们并不确信是那样。好的ORM可以将很多技术自动化,像对象融合(object hydration)、查询批处理、有效地生成查询、热切载入(eager loading)、智能缓存等等,那会让基于ORM的代码和手动编写的代码执行得一样快。
生产率也是关键的问题。使用ORM不是要节省 计算机的时间,而是要节省开发时间——更快地构建应用,消除各种错误、执行好的实践、让快速可靠的测试和部署成为可能。例如,LightSpeed会自动 对查询进行参数化,那和手动编写的SQL相比,会避免大多数SQL注入的攻击。我们都需要花费时间创建模型来实现强验证,或者数据绑定通知,或者编辑回 滚。有了LightSpeed我们努力把这些类型的问题归到“拿来就用(it just work)”一类。从原始的数据访问代码转为使用ORM就像从汇编转为C#或者Java一样。可能你会放弃一点儿性能,但是比你想象的要少,而你换回的是 上百倍的生产效率。
最后一点特别针对.NET ORM的是对LINQ的支持。我们已经大量使用了LINQ,很难想象如何在没有它的情况下工作。所以拥有真正稳定的LINQ提供程序非常重要。构建坏的 LINQ提供程序很难。构建好的LINQ提供程序更难。多年以来我们一直在改善LightSpeed中的LINQ提供程序,这是我们值得自豪的一点。对 LINQ的支持已经成为.NET开发者工具箱中期望得到的特性,所以一种ORM中不支持LINQ或者支持很差都是不可接受的。
InfoQ:LightSpeed支持类似于EF使用POCO实现的代码先行(code-first)之类的功能吗?
JD:模型先行和代码先行在概念上非常类似,它们都是说开发者在数据库结构存 在之前以代码的方式来说明模型。LightSpeed当然支持模型先行,而且早在多年前就已经支持,然而,那依赖于使用LightSpeed的模型设计器 创建和管理数据库的变更,并基于定义的模型来创建类。EF的代码先行比模型先行更进一步,它让开发者可以只编写类本身,然后就可以从那些类生成对数据库的 更新,而不需要设计器。我们几乎没有收到添加这种支持的请求,因为它会造成生产力的极大降低,那是由于需要你手动编写所有应用程序所需的实体,然后才能创 建类。
关于POCO,我们不会把它设置为默认的选项。LightSpeed实体依赖于“Entitiy”基类,坦白说, 这是因为我们相信它会为开发者带来巨大的价值。记住,ORM是与生产力相关的。我们看到喜欢POCO的人们花费多个小时来管理T4模板,只是为了生成支持 的类,比方说INotifyPropertyChanged,或者跟踪改变了的字段,或者处理验证(或者更坏,手动编写所有这些代码而不使用代码生成 器!) 唉,你有更好的方法,不需要手动编写那类代码。我们的经验是,天哪,用额外的继承层次来换取这些内容是很值得的:LightSpeed的开发者通常会喜欢 它,因为他们可以专注于解决实际的问题,而不是手动继承或者编写他们自己的样板代码(plumbing code)。
这么说,分布式场景会从POCO获得很大的益处,因此LightSpeed支持两种方法来进行分布式开发:
- 通过线(wire)和“DistributedUnitOfWork”进行实体序列化,从而开发者可以在客户端编写LINQ查询,然后 LightSpeed会自动把它传送给服务器,运行查询,然后再把结果发送回来。我们还会做一些聪明的事情,像只把变更的实体发送回来,从而让速度更快。 这种方法功能更完整,并且会被视为“有魔力”的。
- DTO——LightSpeed设计器不仅可以为用户生成DTO,而且我们会提供方法,使得把DTO导入到服务器上完全成熟的Entity对象中更加容易。这很简单,不那么神奇,但是有些开发者更喜欢这样。
InfoQ:关于自动迁移情况如何呢?
LightSpeed支持比自动迁移更好的功能。
LightSpeed是唯一一种扩展了Visual Studio,添加了集成的schema迁移管理的ORM。这包括捕获变更,显示存在什么样的迁移,针对数据库执行它们,并生成变更脚本(以任何你喜欢使 用的数据库)。当然,服务器上不应该安装Visual Studio,因此我们对于生产数据库会包含命令行工具来运行迁移操作。或者你可以使用一种API把它集成到应用程序当中。
迁移只是事情的一部分——一旦你确定模型的改变是你所需要的,那么通常就会做出迁移。LightSpeed设计器从 我们发布的时候就支持名为“360度的数据库往返(360 database round tripping)”特性,用户非常喜欢这种特性。它的意思是,如果你是喜欢使用模型先行的开发者,那么你就可以先对领域建模,右键点击“更新数据库”, 然后LightSpeed设计器就会在开发数据库和模型之间执行寻找差异的操作,并让你确认是否想要应用变更。当完成的时候点击“OK”,数据库就更新 了。
但是如果你使用数据库先行的方式呢? 很简单,右键点击你的模型,选择“从数据库更新”,LightSpeed的模型设计器就会找到变更,展示给你,让你确认你是否想要应用到实体上。最神奇的 事情是,你可以使用混合的方式,如果某些开发者喜欢模型先行,而另一些喜欢数据库先行,他们可以按照喜欢的方式工作,一切都可以同时进行,那样就会生效。
InfoQ:你曾经在一篇博文中提到,LightSpeed在单独一个实体模型设计器可以支持最多2000个实体,并且还能够保持用户的友好性,请你说明一下这是如何达到的。
JD:在一个模型中放2000个实体对用户来说永远都不会是友好的,但是我们已经做了很多努力帮助用户使用非常复杂的模型。
例如,我们提供了一种快速的方式在模型中查找你所需要的实体——只需要键入它的名字,我们就会进行过滤,并找到匹 配的实体。然后,你可以对其扩展,以包含相关的实体或者整个集合。如果你想要看到整个子领域——比方说销售或者物流——而不是单独的集合,那么你可以对实 体设置标签,并通过标签来过滤。所以我们很容易就可以从模型返回到你刚刚感兴趣的那几个实体。你还可以通过多个文件来扩展模型——例如,每个子领域一个文 件——那并非是整合的方式,但是,如果多个人员同时操作模型的不同部分,那有助于解决源代码控制的问题。
实体着色是一种看起来很微不足道的特性,但是对于大型的模型能够起到帮助。通常在你的模型中会有相对较少的关键业务实体,而模型的其他部分都围绕这些关键实体。以可区分的颜色来显示那些实体,这样一下子就能够很容易地找到它们——它们在各种噪音中显得很特别。
在低层次,我们还在快速获取数据库元数据方面付出了很多努力。例如,我们避免拉取不需要的表的元数据——当你处理不规则的遗留数据库时,这会导致很大的不同。
所以这意味着即便在数据库更大的情况下,我们也可以高效地完成schema的round-tripping。
InfoQ:对于当前使用NHibernate或者实体框架的应用程序来说,是否有一种简单的迁移方式,而不需要对代码做出太多变更?
JD:这在很大程度上取决于开发者如何建立应用程序的架构。
如 果开发者使用了LINQ(例如,使用实体框架或者LINQ to SQL),那么就很容易。我们有的客户只花费了几个小时,就把构建在实体框架上的大型应用程序转换为LightSpeed。之所以简单,是因为如果查询已 经在LINQ中,那么就不需要重新编写,用户只需要使用LightSpeed UnitOfWork来替换会话对象,把模型迁移到LightSpeed模型,并对应用程序添加一些配置。相反,如果大量查询逻辑都是用 HQL(Hibernate Query Language)编写的,那么你就有大量工作要做!
对于模型迁移来 说,LightSpeed包含了一些特性来帮助把实体框架和LINQ to SQL的模型迁移到LightSpeed。把EDMX文件或者LINQ to SQL模型文件拖拽到LightSpeed模型的界面上,就会让LightSpeed设计器读取模型并自行生成。然而,要记住,模型迁移通常只是过程的开 始而不是结束。测试很重要——例如,你可能发现在LINQ提供程序,特别是带有非常复杂的查询的提供程序中会有区别。
就像在所有迁移过 程中一样,你会想要避免受到目标平台的影响。例如,你可能想要把你的验证代码迁移到集成的验证框架中,设置热切载入(eager load)使你的查询效率更高,诸如此类。但是在一般的LINQ语法和模型导入支持之间,至少尝试迁移到LightSpeed是很容易的,然后就可以看下 它是否适合你的应用程序。
InfoQ:依你所见,哪些通常需要的特性不在ORM的责任范围之内,为什么?
JD:我们遇到过一些开发者,他们希望ORM能够完全取代与数据库交互的工 作。例如,要求ORM管理数据库复制,或者是一些通常是数据库关注的问题。尽管这些特定的特性不在ORM的范围之内,并且理论上可以添加到其中,但是很少 有用户会利用这些特性,因此包含那些特性在成本上是不合算的。大多数那类特性我们是不会支持的。