A-A+

[NHibernate]最佳实践技巧

2015年01月29日 NHibernate教程 评论 1 条 阅读 726 次

设计细颗粒度的持久类并且使用 <component>来实现映射。

使用一个Address持久类来封装 street, suburb, state, postcode. 这将有利于代码重用和简化代码重构(refactoring)的工作。

   对持久类声明标识符属性( identifier properties)

NHibernate中标识符属性是可选的,不过有很多原因来说明你应该使用标识符属性。我们建议标识符应该是“人造”的(自动生成,不涉及业务含义)。 并且不是基本类型。为了最大的灵活性,应该使用Int64或者String类型。

为每个持久类写一个映射文件

不要把所有的持久类映射都写到一个大文件中。把 Eg.Foo 映射到Eg/Foo.hbm.xml中, 在团队开发环境中,这一点显得特别有意义

把映射文件作为资源加载

把映射文件和他们的映射类放在一起,并且在 Visual Studio里设置映射文件为 嵌入式资源(Embedded Resource)

考虑把查询字符串放在程序外面

如果你的查询中调用了非ANSI标准的SQL函数,那么这条实践经验对你适用。把查询字符串放在映射文件中可以让程序具有更好的可移植性。

使用查询参数

就像在ADO.NET编程中一样,应该总是用占位符"?"来替换非常量值,不要在查询中用字符串值来构造非常量值!更好的办法是在查询中使用命名参数。

不要自己来管理ADO.NET connections

NHibernate允许应用程序自己来管理ADO.NET connections,但是应该作为最后没有办法的办法。 如果你不能使用NHibernate内建的connections providers,那么考虑实现自己来实现NHibernate.Connection.IConnectionProvider

考虑使用用户自定义类型(custom type)

假设你有一个.Net类型,来自某些类库,需要被持久化,但是该类没有提供映射操作需要的存取方法。 那么你应该考虑实现 NHibernate.UserTypes.IUserType接口。这种办法使程序代码写起来更加自如, 不再需要考虑类与NHibernate type之间的相互转换。

在性能瓶颈的地方使用硬编码的ADO.NET

在对性能要求很严格的一些系统中,一些操作(例如批量更新和批量删除)也许直接使用ADO.NET会更好,但是请先搞清楚这是否是一个瓶颈, 并且不要想当然认为ADO.NET一定会更快。如果确实需要直接使用ADO.NET, 那么最好打开一个 NHibernate ISession 然后从 ISession获得connection, 按照这种办法你仍然可以使用同样的transaction策略和底层的connection provider。

理解ISession清洗(flushing)

ISession会不时的向数据库同步持久化状态,如果这种操作进行的过于频繁,那么性能会受到一定的影响。 有时候你可以通过禁止自动flushing尽量最小化非必要的flushing操作,或者更进一步,在一个特殊transaction中改变查询和其它操作的顺序。

在三层结构中,考虑使用 SaveOrUpdate()

当使用一个分布式的架构的时候, 你可以把已加载的持久对象在中间层和用户界面层之间来回传递。使用新的session来为每个请求服务, 使用 ISession.Update() 或者 ISession.SaveOrUpdate()来更新对象的持久状态。

在两层结构中,记得自己关闭session

为了得到最佳的可伸缩性,数据库事务(Database Transaction)应该尽可能的短。但是, 程序常常需要实现长时间运行的“业务事务(Application Transaction)”, 包含一个从用户的观点来看的原子操作。这个业务事务可能跨越多次从用户请求到得到反馈的循环。 请使用离线对象(Detached Object),或者在两层结构中,把NHibernate Session从ADO.Net连接中脱离开,下 次需要用的时候再连接上。绝不要在一个Session中包含多次业务事务,否则你的数据可能会过期失效。

不要把异常看成可恢复的

这一点甚至比“最佳实践”还要重要,这是“必备常识”。当异常发生的时候,回滚 ITransaction ,关闭 ISession。 如果你不这样做的话,NHibernate无法保证内存状态精确的反应持久状态。尤其不要使用ISession.Load()来判断一个给定标识符的对象实例在数据库中是否存在, 应该使用Get()

对于关联优先考虑lazy fetching

谨慎的使用主动外连接抓取(eager (outer-join) fetching)。对于大多数没有二级缓存缓存的持久对象的关联,应 该使用代理(proxies)或者具有延迟加载属性的集合(lazy collections)。对于被缓存的对象的关联, 尤其是缓存的命中率非常高的情况下,应该使用outer-join="false",显式的禁止掉eager fetching。 如果那些特殊的确实适合使用outer-join fetch 的场合,请在查询中使用left join。

考虑把NHibernate代码从业务逻辑代码中抽象出来

把NHibernate的数据存取代码隐藏到接口(interface)的后面,组合使用DAO和Thread Local Session模式。 通过NHibernate的IUserType, 你甚至可以用硬编码的ADO.NET来持久化那些本该被NHibernate持久化的类。 (该建议更适用于规模足够大应用软件中,对于那些只有5张表的应用程序并不适合。)

使用与业务有关的键值来实现Equals()GetHashCode()

如果你在Session外比较对象,你必须要实现 Equals()GetHashCode()。在Session内部,Java的对象识别可以值得信赖。 如果你实现了这些方法,不要再使用数据库辨识!瞬时对象不具有标识值,Hibernate会在对象被保存的时候赋予它一个值。 如果对象在被保存的时候位于Set内,hash code就会变化,要约就被违背。为了实现用与业务有关的键值编写 Equals()GetHashCode(), 你应该使用类属性的唯一组合。记住,这个键值只是当对象位于ISet内部时才需要保证稳定且唯一, 并不是在其整个生命周期中都需要(不需要达到数据库主键这样的稳定性)。 绝不要在Equals()比较中使用集合(要考虑延迟装载),这些相关联的类可能被代理过。

不要用怪异的连接映射

多对多连接用得好的例子实际上相当少见。大多数时候你在“连接表”中需要保存额外的信息。这种情况下,用两个指向中介类的一对多的连接比较好。实际上,我们认为绝大多数的连接是一对多和多对一的,你应该谨慎使用其它连接风格,用之前问自己一句,是否真的必须这么做。

标签:

1 条留言  访客:1 条  博主:0 条

  1. avatar 香港云主机

    看看,做个了解吧!

评论已关闭!

Copyright © 极品飞鸽 保留所有权利.   Theme  Ality 蜀ICP备14015766号-1

用户登录

分享到: