词条统计
浏览次数:4880 次
编辑次数:5次 历史版本
最近更新:2013/6/20
创建者:掷鸡蛋者

本文原是论坛帖子,讨论见此处:http://www.wojilu.com/Forum1/Topic/159 


以下讨论的问题可能会有很大的争议,但却是 wojilu ORM 的重要设计思路。

第一部分:一对多、多对多关联

wojilu ORM 支持一对多映射,但不支持多对多。在一对多映射上,wojilu ORM 不支持级联删除,删除需要手工操作。

1) 非常类似于28定律,关联功能只有20%甚至更少的场合才有用处,但却耗费了开发者80%的精力
2) 有一些问题,程序员在开发的时候好不容易搞明白了,但过了几个月却很容易遗忘,比如“什么场合需要用多对多关联,关联之后ORM内部是如何处理的,需要注意什么问题”等等
3) 如果将关联问题作为ORM的内部机制处理,而这个处理机制又有一定的复杂度,这直接导致数月之后,要想维护代码必须回忆ORM本身的知识
4) 我主张手工编码维护多对多关联,而不是由ORM内部处理。手工编码虽然多了一些代码量,但你可以将这些多出来的代码看做是多对多关联的文档(“代码即文档”),在数月甚至一两年之后,你完全可以通过代码(“代码即文档”)了解对象之间的持久化关系。——这是处理复杂对象关系的最好方式
5) 实际上对于互联网应用来说,多对多真的没有什么用处

比如一个用户有多个tag,而一个tag也有多个用户,这是典型的多对多关系。但在应用程序中却几乎不会出现 user.AllTags 这样的用法:一个用户有几十个tag的情况下, user.AllTags 似乎没有问题;但对于一个强壮的、可扩展的系统来说,应该考虑到(实际上也确实)用户的tag可能上百甚至上千(疯狂的用户甚至会上万),这时候 user.AllTags 的用法已经完全没有意义。正确的、强壮的用法是通过 UserTagShip 对象进行分页的数据处理。


总结:

a)手工编码实现“一对多、多对多”关联,将对象之间的复杂关系“通过代码实现文档化”,增强可维护性
b)用关系对象的分页方案代替“一对多、多对多”对象检索,才是强壮的、具有普遍意义的处理办法


看到许多orm使用者,不断讨论如何正确的维护双向关系,如何避免其中的问题,我就想:明明可以用代码轻松描述的事情(代码即文档),为什么一定要搞得这么累呢?尤其是以快速开发这样糟糕的借口?

更加重要的是,级联删除对于关键数据来说,应该属于业务的核心逻辑,不是可以随便就级联删除掉的。妥善的业务需求往往是,如果实体A需要物理删除了,关联的实体B只是打上IsDeleted=1的标记,放入回收站,而不是一起物理删除掉。

这就是 wojilu ORM 的观点:实体的关系如何维护,应该属于业务逻辑领域,需要手动代码描述(代码即文档!)。它不应该是ORM的必然职责。虽然ORM可以提供这样的选择,但程序员应该谨慎并且尽量少的使用。手动维护并不需要多少代码,但却能让业务逻辑更加清晰易懂。而不是在半年之后的某天,开始维护的时候,心中花上十几分钟甚至数小时琢磨ORM内部是如何处理的。

而 wojilu ORM 之所以简洁易用,很大程度上和它在处理对象关联上的简化做法有关。


举个例子:


如果是“作者与书”这种多对多关联,最好的做法是,定义一个 AuthorBookShip 对象(关系对象),处理多对多关联,比如:

public class AuthorBookShip : ObjectBase{

public Author Author {get;set;}

public Book Book {get;set;}

// 其他属性。。。

}

然后通过这个AuthorBookShip 关系对象,进行相关的查询。


最终,对象之间的关联关系,是通过代码直接描述的,而不是由ORM内部的规则描述,理解起来应该更加容易。


第二部分:继承和多态

wojilu ORM 支持继承,采取"一个类一个表(子类和父类都有对应的表)"的方式,但是:

1) 继承和多态实际上是面向对象编程最精彩的地方,也是最能发挥面向对象编程优势的地方;
2) 但继承和多态有应用的场合限制,使用不当会带来难以预料的复杂度;
3) 根据对象的持久与否,我将对象分成“不需要持久化的对象”和“需要持久化的对象”两种;
4) 对于前者,可以大量使用继承和多态设计;使用得越多,就越能发挥出面向对象编程的威力;
5) 对于后者(需要持久到数据库的对象),应该尽量扁平化设计,不要继承;为了解藕,将多态的地方用接口代替。

总结:在 ORM 中尽量不要用继承,保持简单,kiss 它(keep it simple and stupid)。