Hello World
Spiga

我对NHibernate的感受(4):令人欣喜的Interceptor机制

2009-10-13 13:45 by 老赵, 20775 visits

之前谈了NHibernate的几个方面,似乎抱怨的居多,不过这次我想谈一下我对Interceptor的感受,则基本上都是好话了。这并不一定是说Interceptor设计的又多么好(事实上它使用起来还是挺麻烦的),但是这的确也是我认为NHibernate超越LINQ to SQL,尤其是Entity Framework的又一个重要方面——因为Entity Framework本身也已经不差了。更重要的是,Interceptor机制让我得以实现我“理想中的”数据访问功能。当然现在只是浅尝辄止一番,我打算以后再慢慢地,详细地谈谈我所满意的“数据访问层”设计。

Interceptor的作用是为NHIbernate中的Session(如LINQ to SQL中的DataContext)增加一个“拦截器”,这个拦截器会捕获到Session各个阶段所发生的事情,并且有机会访问到它们所牵涉到的数据。例如:

  • OnLoad:当前Session加载了哪些对象
  • OnDelete:当前Session删除了哪些对象
  • OnSave:Session保存了哪些对象
  • PostFlush:当前Session的Flush已经完成了

关于Interceptor功能,NHibernate的文档上只是一笔带过,更详细的信息可以参考Hibernate的API说明。由于Interceptor可以记录到Session中所经过的所有对象,因此它可以做的事情就很多了。例如已经被人写滥的“日志记录”或“审查(Audit)”,但好像少有人把它真正用在数据访问的功能上。我了解Interceptor之后感觉非常兴奋,因为终于有人为我想要实现的功能做好铺垫了。这个功能便是“结合其它数据访问机制”。

说到数据访问层,大家肯定知道它的职责是“从数据源读写数据”。在很长一段时间内,这个数据源基本上就是关系型数据库,无论是商业的SQL Server,Oracle还是开源的MySQL,PostgreSQL,万变不离其宗。于是有人提出了SqlHelper,Data Access Block这样的数据库读取辅助工具、iBatis这样的SQL-对象映射工具(我不认为它是ORM)、还有NHibernate、LINQ to SQL这样的ORM框架。但是无论是什么工具,无论怎么访问,数据访问层作的事情也无非是SQL、SQL、SQL,然后再把得到的数据集转化为内存中的对象。

但是到了如今的时代,数据访问层所负责的数据源已经远远不止这些了。例如,许超前在博客上介绍了手机之家的数据访问层功能,这是其中一幅截图:

这是个目前比较典型的数据访问层功能,它除了访问关系型数据库之外,可能还需要访问异步消息队列(如MSMQ、ActiveMQ)、K/V存储(如Memcached,Tokyo Cabinet)或是其他文档型数据库(如MongoDB、CouchDB)。也就是说,我们在将数据存入关系型数据库的时候,可能还要添加一条异步消息,或是同步到其他存储方式中——而Interceptor便为我们提供了这样的可能。

例如,这是一个ArticleInterceptor的结构:

public class ArticleInterceptor : EmptyInterceptor
{
    public override bool OnLoad(object entity, object id, ...)
    {
        var article = entity as Article;
        if (article == null) return false;

        // 记下所有加载的ArticleID

        return false;
    }

    public override void OnDelete(object entity, object id, ...)
    {
        var article = entity as Article;
        if (article == null) return;

        // 记下所有删除的ArticleID
    }

    public override void PostFlush(ICollection entities)
    {
        foreach (var article in entities.OfType<Article>())
        {
            // 进行对比,将修改,创建或删除的Article内容提交至Lucene索引
        }
    }
}

NHibernate的优点之一是“自动跟踪”对象状态,而Interceptor也给我们这样插一手的机会。利用如上的ArticleInterceptor,我们就可以知道Session中修改了哪些Article对象,并且在Flush操作之后同步至Lucene索引。当然,这只是一个示例(事实上Lucene索引只能接受单个线程的写),具体情况需要根据各自需求来进行改变。而其中更关键的问题,可能便是“事务”了。

PostFlush会在Session的Flush操作完成之后调用,但是这时候当前数据库事务可能并没有完成——这可能是因为程序在使用NHibernate的时候选择了外部控制事务的方式,这个事务可能跨Session等等。于是,如果是像外部数据源的更新,它往往不会“卷入”当前的数据库事务(可能是做不到,也可能是故意避免分布式事务),因此如果它在PostFlush操作中就完成的写入,那么如果当前事务回滚之后,外部数据源的更新能一起撤销吗?

不过,对于程序员来说,这些应该都不是问题。例如,我们可以在PostFlush之后“纪录”需要更新的内容,然后在整个事务已经确保成功的时候才写入外部数据源。总之,要根据不同项目的需求来确定。

利用NHibernate的Interceptor,其实我们还可以在这方面做更多的文章。例如,我们可以把Article对象的Content数据放入K/V存储内,这样可以减少关系型数据库中表的每一行的大小,有利于性能的提高。然后在加载Article对象的时候,我们在Interceptor的OnLoad方法中可以再将Article的Content数据读回从K/V存储内读取回来。

因此在我看来,我们使用Interceptor,完全可以将NHibernate这个ORM框架打造成一个Object-Any-Mapping工具,将对象与“任何”存储方式进行映射。在大约两个月前,我想,如果我真要构建一个这样的OAM框架,我又该怎么做呢?

只不过,我想着想着最后放弃了。因为这样的框架实在过于复杂。因为在我的想法中,如果使用通用的OAM框架,需要能够支持多种数据源,并且可以将一个对象分为多个部分,分别放入不同的数据源中。在查询的时候,还可以根据不同数据源的特征选择查询方式(例如,全文查找去Lucene,根据ID获取数据则通过K/V存储,其他可能就是关系型数据库或是文档数据库了)——甚至于还会自动从不同数据源中获取数据后,在内存中作JOIN。

这些都是实际开发过程中所需要的真实功能,但是一个像NHibernate这样的ORM框架已经如此复杂了,这样的OAM的“可行性”如何……我想大家也都有思考结果。虽然Hibernate也已经有一些通用的框架,如Hiberante Search集成了Lucene,Hibernate Sharding可以支持自动的数据库划分,但是它们的“通用性”真有Hibernate这样高吗?我对此表示怀疑。

因此,就目前而言,我认为最可行的方式,可能就是基于NHibernate这样强有力的ORM框架打造的数据访问层,至于内部“在哪个时机选择什么样的数据操作方式”,还是由数据访问层本身根据自身需要来吧。由于不需要“通用”,这样的数据访问层可以变得相对简单很多。

由于存储方式的不断出现,对合适的操作选择合适的存储方式已经是一个重要的课题,因此数据访问层的构建也已经越来越重要,它不仅仅是无聊的CRUD操作了——反而是对于一些项目由于没有复杂的逻辑,它的“业务逻辑层”会显得非常薄。您的数据访问层是如何构建的,能分享一下这方面的经验吗?

在今后的文章中,我也会有更多展开的。

相关文章

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

69 条回复

  1. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-13 14:02:00

    这个应该是很基本的功能吧,即使是我自己做的超轻量级的数据库访问帮助工具中也有统一的SQL执行审查。

  2. 菌哥
    *.*.*.*
    链接

    菌哥 2009-10-13 14:12:00

    这就是NH的AOP功能吗?

  3. 老赵
    admin
    链接

    老赵 2009-10-13 14:14:00

    @Ivony...
    这不是SQL执行审查……还有这个功能LINQ to SQL,Entity Framework都没有。

  4. 老赵
    admin
    链接

    老赵 2009-10-13 14:18:00

    @菌哥
    类似吧,不过其实和AOP无关,就是个横切的机制。

  5. 道法自然
    *.*.*.*
    链接

    道法自然 2009-10-13 14:28:00

    NH使用一大堆的virtual就是用于生成动态代理,然后插入拦截机代码。不过老赵提的这个拦截机未必是AOP的拦截机了,估计只有看过源代码才知道。

    类似实现老赵提到的这种功能,我们的做法是采用一个Bus机制,即将数据收集后推入到Bus总线,有不同的Listener来处理这个数据,如保存到Repository、产生Alert、发送邮件等。

    这个Interceptor的功能有点类似一个Listener,我们可以依赖这个Listener再广播一下数据。至于其它应用,我也没有接触过了。

    利用动态代理插入拦截机代码的想法,确实很酷,也能够在实际中解决很多问题,令人遗憾的就是在.NET中需要声明一堆virtual。关于virtual,我记得老赵原来就讨论过了。

  6. 老赵
    admin
    链接

    老赵 2009-10-13 14:34:00

    @道法自然
    嗯,我说的不是virtual的作用,virtual也不是为了interceptor的。
    其实很多时候,框架提供一个横切的机制是很好用的。
    而且,这样的机制经过设计,功能会更加灵活,而不是机械的AOP。

  7. lexc[未注册用户]
    *.*.*.*
    链接

    lexc[未注册用户] 2009-10-13 14:40:00

    没啥挑的,挑个错字吧:万变不离其宗

  8. 道法自然
    *.*.*.*
    链接

    道法自然 2009-10-13 14:42:00

    @Jeffrey Zhao

    我的意思是,实现AOP原理之一就是使用动态代理 + 拦截机。在.NET应用这样的AOP框架时,必须声明Virtual,比较烦。

  9. 老赵
    admin
    链接

    老赵 2009-10-13 14:48:00

    @道法自然
    是的……不过还真没啥办法……

  10. 道法自然
    *.*.*.*
    链接

    道法自然 2009-10-13 14:53:00

    按着老赵帖子,顺便给大家出一个小问题。

    有一个绑定线程的类A,具有一个SendMessage和其它方法。A中的所有方法必须由A的线程自己执行。
    A
    {
    SendMessage(msg);
    Do1();
    Do2();
    }
    那么另一个实例创建了A的实例a,要使a执行Do1方法事,它需要这样做:InvokeMessage invokeMsg = new InvokeMessage("Do1", parameters); a.SendMessage(invokeMsg);

    如果一个系统有很多像A的对象,那么,使用这种方式编码,将带来不小的问题,因为所有的调用都没有“强类型”,而且书写麻烦。如何解决呢?

  11. 不若相忘于江湖
    *.*.*.*
    链接

    不若相忘于江湖 2009-10-13 14:57:00



    老赵. 你咋这么牛呢.

  12. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-13 14:57:00

    这就完全可以用lambda Expression包装了么。


    a.Invoke( host => host.Do1( abcdefg ) );

    A
    {
    public void Invoke( Expresion<Action<A>> expression );
    }

    不过这种需求,其实那个SendMessage完全可以接受委托么。为什么一定要用InvokeMessage呢?

  13. 道法自然
    *.*.*.*
    链接

    道法自然 2009-10-13 15:01:00

    @Ivony...

    强悍,不过,如果用户使用这种方式编码的话,还是很麻烦。还有一个使用起来最简单的方式。

    用InvokeMessage,是为了更加让人容易理解。

  14. 老赵
    admin
    链接

    老赵 2009-10-13 15:14:00

    @道法自然

    class A
    {
        SendMessage(Expression<Action<A>> msg);
    }
    

  15. 道法自然
    *.*.*.*
    链接

    道法自然 2009-10-13 15:28:00

    @Jeffrey Zhao

    凡是需要调用SendMessage来执行Do1的方式,对用户来讲都不太直观。我们实现的方式如下:

    Class A
    {
    private MessageQueue _queue;
    public virtual Do1();
    public virtual Do2();
    ......
    }

    用户使用方式:
    A a = Factory.Build<A>();
    a.Do1();

    我想大家都会喜欢这种方式来使a线程执行Do1方法的。实现原理就是你说的拦截机。a.Do1调用后被拦截机拦截,它将调用转换成消息后,发送到a的MessageQueue中。a的线程一直处理MQ。

  16. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-13 15:34:00

    两个侧面。。。。

    使用override实现的拦截具有它的先天局限,例如必须是virtual不能sealed,还有,实例污染,换言之必须使用包装类的实例,而不能使用A的实例,这会造成多态方面的问题。

    例如A的Wrapper是WrapperA继承于A,B派生于A,B的Wrapper只能继承于B而不能继承于WrpperA,所以WrapperB就丢失了is WrapperA的逻辑。

  17. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-13 15:36:00

    任何实现方式都有其局限性,这个问题最好还是CLR内建拦截机制,其实这应该不难实现。。。。。


    不过当大家的思想进化到那个程度后,语言语法上的跟进应该就会是水到渠成的事情。


    顺回老赵,因为我那个帮助器只是负责执行SQL语句而不负责ORM等工作,所以它所能提供给外界的也就只有SQL执行审查了。

    Entity Framework和LINQ to SQL没有这样的功能应该说是比较奇怪的事情。

  18. 老赵
    admin
    链接

    老赵 2009-10-13 15:49:00

    @Ivony...
    不过这个功能的确是挺耗设计的东西,而且其实还真不是ORM必须的。
    只是个bonus,但这个bonus现在看来就无比游泳了。

  19. craboYang
    *.*.*.*
    链接

    craboYang 2009-10-13 16:06:00

    @道法自然

    “我的意思是,实现AOP原理之一就是使用动态代理 + 拦截机。在.NET应用这样的AOP框架时,必须声明Virtual,比较烦。”


    AOP主要用于方法拦截,virtual用于属性声明, 也可以说AOP毫无关系(也能说有),哪来的烦?

  20. 道法自然
    *.*.*.*
    链接

    道法自然 2009-10-13 16:14:00

    @craboYang

    没有声明virtual的方法能被拦截吗?和AOP没关系吗?

  21. Karron Qiu
    *.*.*.*
    链接

    Karron Qiu 2009-10-13 16:18:00

    在nh2 里面 interceptor 已经被 event listener 所取代了. interceptor一个session只有一个有效, 并且包含了所有事件, 非常不利于扩展. 而event listener就完全避免了这些问题, 并且提供了更多的扩展点. 建议看看event listener.

  22. 老赵
    admin
    链接

    老赵 2009-10-13 16:22:00

    @Karron Qiu
    嗯嗯,好啊,有Event Listener那就更好了。
    一个session只有一个有效问题也不大,最多搞一个AggregateInterceptor咯,也是很常见的解决方案。

  23. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2009-10-13 16:23:00

    好像nh的拦截器和事件并没这么深奥吧,跟aop根本扯不上.就是在每个操作的时候多了一些设计,加了一些回调方法.
    而且interceptor 一次性要全部执行,没事件灵活

  24. 老赵
    admin
    链接

    老赵 2009-10-13 16:27:00

    @Clingingboy
    是啊,这点推测的出来。

  25. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2009-10-13 16:31:00

    我想问一下,在nh更新数据时,如果一个实体类有很多属性要更新,不知道有什么快捷的方法。每次这个赋值感觉很无聊,浪费时间。。。

  26. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-13 16:35:00

    Clingingboy:我想问一下,在nh更新数据时,如果一个实体类有很多属性要更新,不知道有什么快捷的方法。每次这个赋值感觉很无聊,浪费时间。。。




    不考虑效率用反射,考虑效率用Emit或CodeDom。

  27. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2009-10-13 16:43:00

    我统一反射...

  28. 老赵
    admin
    链接

    老赵 2009-10-13 16:54:00

    @Clingingboy
    总归要赋一次值的啊,不赋值谁知道你在改什么呢?

  29. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 16:56:00

    推荐 事件,这个,还不如Castle的拦截器呢

  30. 老赵
    admin
    链接

    老赵 2009-10-13 17:12:00

    @李永京
    Interceptor和Castle的拦截器有任何可以比较的地方吗?

  31. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2009-10-13 17:16:00

    @Jeffrey Zhao
    我的想法不通过session取entity,而是直接在外部传入一个entity,可以自动匹配键值,然后也不检查数据库是否存在这条数据,或者通过什么扩展的方法,然后直接更新.
    不然模块一多,一堆相同的代码写起来很无聊...

  32. 老赵
    admin
    链接

    老赵 2009-10-13 17:51:00

    @Clingingboy
    说不定你可以关注一下AutoMapper这个项目?

  33. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 18:58:00

    Jeffrey Zhao:
    @Clingingboy
    说不定你可以关注一下AutoMapper这个项目?


    AutoMapper项目只是Domain->DTO单向Map,还不如自己写个扩展方法就搞定了

  34. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 19:03:00

    Jeffrey Zhao:
    @李永京
    Interceptor和Castle的拦截器有任何可以比较的地方吗?


    NHibernate机制就是监听机制。处处监听~~~
    在NHibernate2.0新增了EventListener :这一功能使我们在NHibernate执行操作之前或之后能够拦截操作。1.2版本的NHibernate只可以使用接口ILifecycle和IInterceptors拦截 。NHibernate2.0以上可以与NHibernate在更低水平“对话”,在数据保存之前或者之后拦截。不过使用拦截还是用Castle/LinFu的拦截器比较多,AOP啊。

  35. 小No
    *.*.*.*
    链接

    小No 2009-10-13 21:37:00

    道法自然:
    @Jeffrey Zhao

    我的意思是,实现AOP原理之一就是使用动态代理 + 拦截机。在.NET应用这样的AOP框架时,必须声明Virtual,比较烦。



    PostSharp 的AOP实现方式没有用动态代理,而是利用MSBuild在编译的时候注入代码,方法不用声明为Virtual

  36. 小No
    *.*.*.*
    链接

    小No 2009-10-13 21:39:00

    SubSonic 3.0好像也有类似的功能

  37. 老赵
    admin
    链接

    老赵 2009-10-13 21:39:00

    @李永京
    是啊,这是NH设计出来的监听机制,我不觉得和Castle有什么关系,无论是实现方式和功能都是不同的。
    唯一相同的也就是“横切”两个字吧。

  38. 老赵
    admin
    链接

    老赵 2009-10-13 21:40:00

    @李永京
    AutoMapper是对象和对象间的Map,不管啥Domain还是DTO。
    还有,Domain和DTO有啥区别?为啥不用Domain直接Map去数据库?
    我觉得搞Domain以外的DTO,就是自己给自己找麻烦阿。
    就好比,根据DDD设计之后,一切都是Domain,哪里有什么DTO啊。

  39. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 21:46:00

    @Jeffrey Zhao
    NHibernate可是利用Ioc框架Castle/LinFu/Spring.Net的DynamicProxy.IInterceptor功能实现延迟加载的,为此NHibernate还专门提供了这三个的Adapters。我想EventListener才是NHibernate设计的机制。

  40. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 21:49:00

    @Jeffrey Zhao
    使用WCF用DTO作为数据传输对象啊,难道服务间传输直接暴露Domain,Domain的东西很多的,比如关联、属性。我也不想用DTO啊。

  41. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 21:51:00

    @Jeffrey Zhao
    DDD中,Domain也不是整个架构的全部,还有Service、Repository。

  42. 不是整个架构[未注册用户]
    *.*.*.*
    链接

    不是整个架构[未注册用户] 2009-10-13 21:55:00

    老赵你怎么不自己写个ORM框架 ?

  43. 老赵
    admin
    链接

    老赵 2009-10-13 22:09:00

    @不是整个架构
    有NHibernate为什么要自己写啊。

  44. 老赵
    admin
    链接

    老赵 2009-10-13 22:09:00

    @李永京
    Service,Repostory我当然知道,但是不需要DTO。
    不过你说用WCF对外接口,可能的确需要额外的DTO吧,我没有考虑到,呵呵。

  45. 老赵
    admin
    链接

    老赵 2009-10-13 22:11:00

    @李永京
    你说的这些都没错,但是……延迟加载和Interceptor有什么关系?
    这里说的好像都是用在Session上的Interceptor吧。

  46. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 22:15:00

    @Jeffrey Zhao
    恩恩,是没关系,一个是NHibernate.IInterceptor,一个是DynamicProxy.IInterceptor

  47. 李永京
    *.*.*.*
    链接

    李永京 2009-10-13 22:22:00

    Jeffrey Zhao:
    @李永京
    Service,Repostory我当然知道,但是不需要DTO。
    不过你说用WCF对外接口,可能的确需要额外的DTO吧,我没有考虑到,呵呵。


    其实也不需要DTO,这种反模式太垃圾了,也是我们套用了前人的顽固思想。我试写了一下,WCF直接传递Domain,动了大量手脚还支持延迟加载,哈哈

  48. Jerry Qian
    *.*.*.*
    链接

    Jerry Qian 2009-10-14 09:28:00

    老赵,您买E文书是从amazon用信用卡买的吗?快不快啊,好像还提供买旧书的服务?呵呵

  49. 老赵
    admin
    链接

    老赵 2009-10-14 09:46:00

    @李永京
    把Domain当作DataContract,然后在配置/标记上做手脚?

  50. 老赵
    admin
    链接

    老赵 2009-10-14 09:47:00

    @Jerry Qian
    信用卡,很……不快,建议找美国朋友回国,或一些外企朋友带。

  51. jsntcwd[未注册用户]
    *.*.*.*
    链接

    jsntcwd[未注册用户] 2009-10-14 10:30:00

    请教一下各位大哥:

    一个大型项目,要求响应速度很高,这时引入
    NHibernate进行开发是否正确?

    一直有些搞不清NHibernate适用于哪些场景的开发?

    谢谢。。。

  52. 老赵
    admin
    链接

    老赵 2009-10-14 11:15:00

    @jsntcwd
    NHibernate不会影响性能,放心用吧。

  53. jaygor
    *.*.*.*
    链接

    jaygor 2009-10-14 11:35:00

    李永京:

    Jeffrey Zhao:
    @李永京
    Service,Repostory我当然知道,但是不需要DTO。
    不过你说用WCF对外接口,可能的确需要额外的DTO吧,我没有考虑到,呵呵。


    其实也不需要DTO,这种反模式太垃圾了,也是我们套用了前人的顽固思想。我试写了一下,WCF直接传递Domain,动了大量手脚还支持延迟加载,哈哈


    DTO还是有一定的存在价值的吧,比如是跨平台的数据传输呢?我想.net做Client端,java做Server端呢?

  54. 老赵
    admin
    链接

    老赵 2009-10-14 11:38:00

    @jaygor
    DTO是指专门用于携带数据的对象,Domain也是携带数据的对象,只是不“专门”而已,对于跨平台数据传输来说,没有任何差别的。

  55. jaygor
    *.*.*.*
    链接

    jaygor 2009-10-14 12:24:00

    还是有一些差别吧。
    我认为,DTO是“反模式”的这个观点,要加上一个定语:从DDD和XP的角度来说。

    DTO通常是“量身定制”,比较薄,而Domain Model较厚,由于跨平台不能lazy load,所以“厚”的Domain Model影响传输效率。

    而从开发模式的角度来说,DTO的思想也未必一无是处,至少DTO可以解耦Persentation层与Domain层,对水平切割的多人并行开发有好处。

  56. heros
    *.*.*.*
    链接

    heros 2009-10-14 12:25:00

    Domain虽然也是数据对象,但用在服务层对外数据分发上还是显得太臃肿了。如果还有一些附加信息要分发,是不是还要在domain中附加新的非domain类型呢?dto就是用来解耦domain,services,clients的单纯数据对象。

  57. heros
    *.*.*.*
    链接

    heros 2009-10-14 12:27:00

    从职责角度来看,domain用来描述领域信息和关系的,并不是设计用来做分发传递用的。

  58. 老赵
    admin
    链接

    老赵 2009-10-14 12:59:00

    @heros
    在对外分发的时候,可以对Domain做标记,让它序列化成不同的样子啊。用DTO就好比手动作了转化,做标记相当于自动进行了。
    所以我认为除非必要,否则不要额外使用DTO。

  59. 李永京
    *.*.*.*
    链接

    李永京 2009-10-14 13:10:00

    [DataContract(Name = "XXXClass")]和 [DataMember]确实很方便,DTO不就是包裹了一下Domain么,有的Domain属性不需要传输,不加 [DataMember]就可以了,有的情况例如DTO取多个Domain的几个属性,我们之间传那几个Domain不就可以了,不是在分布式或者跨平台,我想DTO没什么必要,转换也要花费很多性能的吧,试想一个类有10000多条集合,那不是转死了啊。

  60. heros
    *.*.*.*
    链接

    heros 2009-10-14 19:44:00

    怎么说呢,我觉得domain不应该有dto的职责。硬是拿来传递了,也没什么错。其实对现有的domain做标记也是在构造dto的过程。新建的类也好,加标记的也罢,目的还是一样,构建dto。毕竟domain不是dto。
    @李永京
    "DTO不就是包裹了一下Domain么",这个说法可就不合适咯。dto和domain在代码和内容是很像。但没有必然的关系。
    我觉得它们的关系就像"雷锋"和"雷锋塔"的关系,看上去很相像,但本质不搭噶。

    如果因为代码需要,传递一些domain无法描述的信息。还是要构建dto。

  61. Y-Y[未注册用户]
    *.*.*.*
    链接

    Y-Y[未注册用户] 2009-10-16 00:18:00

    老赵你好,能否开个主题讨论一下WEB在线人数统计及单点登陆方面的问题呀

  62. chenleinet
    *.*.*.*
    链接

    chenleinet 2009-10-18 01:03:00

    感觉就像看神在聊天,我也要成为神

  63. sunnyboy[未注册用户]
    *.*.*.*
    链接

    sunnyboy[未注册用户] 2009-10-22 16:56:00

    请问下:使用NHibernate来做大型网站的数据访问层,NHibernate太复杂了,是否会影响网站的性能呢,请问老赵你的《我的衣橱》网站使用了ORM框架吗?谢谢!有时间能写一篇如何搭建一个成功的大型网站的文章吗?

  64. 老赵
    admin
    链接

    老赵 2009-10-22 17:08:00

    @sunnyboy
    都是哪里听来的说法,说ORM会影响性能,不适合大型网站啊。
    网站越大型,性能关键就越不在程序这端,在于架构和设计方面。

  65. sunnyboy[未注册用户]
    *.*.*.*
    链接

    sunnyboy[未注册用户] 2009-10-22 17:18:00

    @Jeffrey Zhao
    因为大型的网站架构我没有接触过,所以就存在误解,赵老师有时间可以在你的博客上发布一篇关于网站架构的文章吗?我现在很想了解这方面的知识,希望赵老师能帮助下!

  66. ssssmmm[未注册用户]
    *.*.*.*
    链接

    ssssmmm[未注册用户] 2009-10-22 17:21:00

    btw: DTO不一定只是包裹“一个”Domain吧?

  67. ssssmmm[未注册用户]
    *.*.*.*
    链接

    ssssmmm[未注册用户] 2009-10-22 17:21:00

    @李永京

    李永京:[DataContract(Name = "XXXClass")]和 [DataMember]确实很方便,DTO不就是包裹了一下Domain么,有的Domain属性不需要传输,不加 [DataMember]就可以了,有的情况例如DTO取多个Domain的几个属性,我们之间传那几个Domain不就可以了,不是在分布式或者跨平台,我想DTO没什么必要,转换也要花费很多性能的吧,试想一个类有10000多条集合,那不是转死了啊。


    但是这么做,一个Domain对象就只能对应一种DTO,比如经常要弄个DTO把自己的某些属性和关联的某对象的一些属性取出来成一个对象传送,但是对不同的场合,要拿的字段是不一样的(DTO主要是为了传输性能),直接标在domain上,那不是就只能是一个Domain对应一个DTO了?

  68. cnbloger
    *.*.*.*
    链接

    cnbloger 2009-11-09 09:01:00

    老赵,请教一个问题。NHIbernate中的session在使用时需不需要显示关闭,比如:
    using (_session = _helper.GetSession)
    {}
    有没有标示是否关闭的属性?谢谢!
    因为using以后 _session!=null。

  69. bigCat
    117.39.25.*
    链接

    bigCat 2010-06-28 15:53:00

    我的项目中的在使用一个Genome.Net的ORM框架,用了3年了,感觉功能还不错,不过不是免费开源的。

    • Supports the .NET Framework (versions 2.0 to 4.0)
    • Fully embraces LINQ as its primary query language (Visual Studio 2008/.NET 3.5 or later)
    • Tightly integrates with Visual Studio 2005, 2008 and 2010
    • Supports various database platforms (MS-SQL, Oracle, IBM DB2, SQLite)
    • Supports both approaches: forward engineering from domain models, reverse engineering from databases。

    有兴趣的朋友们可以去他的网站看一下:http://www.Genom-e.com

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我