ActiveRecord充分封装了NHibernate,要想充分地使用ActiveRecord必须要了解NHibernate的持久化相关知识。
了解Sessions(会话)
NHibernate使用session来管理实体的相关操作,ActiveRecord封装了NHibernate的session管理代码,所以有必要了解下NHibernate的session
session相当于NHibernate的一个工作单元,一个客户端连接到一个session时,以后的实体的相关操作都是通过这个session来与数据库进行交互的。
出于性能的考虑,session并不会实时地与数据库进行交互,而是延迟到最后的实体操作完成后才统一地与数据库进行交互。当session中有实体的字段改变时,可调用flushing与数据库进行同步。
session有自己的事务管理机制。
实体的属性
为了描述持久化对象不同时期的不同的状态,以下有多个名称来区别。
相对于数据库来说:如果数据库存在该对象,但内存中不存在则称为non-existant,如果数据库与内存中都存在则称为existant。
相对于实体来说:对象可以有activated 和passivated
相对于持久化来说:如果数据库存在该对象对应的数据则称对象为persistant(持久化对象),若数据库不存在则称为transient (临时对象)
对于session来说:如果一个对象是在session中的(接受session的管理)称为attached,否则称为detached
一个对象如果修改了则称为changed,否则称为unchanged
实体状态
“实体”这个词是为了描述对象与数据库记录结合的状态
状态 | 说明 |
---|---|
Non-existant | 数据库与内存中均不存在该实体 |
Transient | 内存中存在该实体,但数据库中不存在并且和数据库无联系 |
Unsaved | 内存中存在该尸体,数据库还不存在,但准备插入数据库 |
Persistant | 数据库与内存中均存在该实体 |
Unchanged | 一个未改变的持久化过的实体 |
Changed (Dirty) | 一个未保存的改变过的持久化实体。通过调用flushing来同步实体中改变的字段到数据库 |
Detached | 未接受会话管理的实体 |
Deleted | 持久化的实体,但被删除,数据库中不存在,只存在于内存中,调用flushing之后状态会变为Transient |
Stale | 当一个改变过的实体对应的数据库记录在另一个会话中被修改时,此时这个实体无法同步到数据库 |
操作状态
ActiveRecord所有实体状态转化的操作均通过调用方自己调用代码触发
操作 | 说明 |
---|---|
new | 创建一个实体 |
change | 修改一个实体 |
flush | 同步数据库与内存中的数据 |
ext. change | 另一个session修改一个实体 |
常见的使用场景
建议阅读完全的使用场景,便于以后特定的使用场景的应用。
普通的CRUD操作场景
此场景讨论实体的基本使用。
首先创建一个实体,实例化一个实体,此时这个实体状态为Transient(临时)。然后调用entity.Save()或entity.Create(),此时状态变为UnSaved,最后session会自动调用flushing同步数据到数据库中,此时数据就被保存。
注意:建议主键映射不要使用本地的主键自动生成类型(比如SQLServer使用IDENTITY
)。因为当ActiveRecord调用Create或者Save后,如果数据库生成的自增值已被使用,将会有意想不到的错误。显示地调用scope.Flush()会影响数据库的自增值的长生。
如果数据库中数据已经被创建,可通过调用Entity.Find(key)来获取实体,获取的实体可通过Entity.Update来更新。对于删除可调用Entity.Delete()或者Entity.Delete(key)
向导和工作流的场景有共同的特征:即要求数据操作必须统一地执行,相当于将一个session中的所有操作均提交,此时如果session中有实体不需要一起提交可调用 scope.Evict(entity),这样这个实体就不会同步到数据库向导或者工作流场景
并发编辑
当应用程序存在多个客户端的时候就会存在对于数据库数据的并发控制
从理论上讲,你可以选择使用悲观或乐观锁定。当悲观锁定时,一条记录在编辑时,其它用户均不能编辑此记录。乐观锁定使用检测版本号或时间戳来保存更改记录。这意味着检测多个用户可以同时编辑同个对象,但是只允许相同标识的记录提交。ActiveRecord支持悲观锁定,尽管它通常是不适合应用程序。乐观锁定可以使用ActiveRecord类中的特殊字段来实现。
ActiveRecord可通过加版本号或时间戳来实现悲观锁,当然这样只能起到防范作用,无法提供恢复的措施。最常用的策略是客户端向用户展示更新后和他自己的版本。
无需显示调用数据操作
using (new SessionScope())
{
Blog blog = Blog.FindFirst();
blog.Name = "new Name";
// blog.Save(); // 不需要
}
当使用SessionScope时,客户端无需显示调用数据库的操作。