重点

NHIbernate处理只读对象的方式可能和你在别处看到的不同。不正确的使用方式可能造成不可预料的结果。

当一个实体是只读的时候:

  • NHIbernate不会对实体的简单属性和单向关联数据检查数据是否是脏数据
  • NHibernate不会对实体的简单属性和单向关联数据进行更新操作
  • NHibernate不会更新只读对象的版本信息,尽管实体的简单属性和单向关联数据发生了改变
  • 在某些情况下,NHibernate对待一些只读实体类型和费只读类型是一样的:

  • Nhibernate级联操作定义在实体mapping中的关联对象
  • Nhibernate在实体包含的集合被修改之后会更新它的版本信息
  • 只读实体被删除
  • 尽管一个实体不是只读的,它的管理集合对象如果包含只读实体,它还是会受到影响。

    NHibernate会对只读实体进行一些优化:

  • 它节约了执行时间,因为不需要对实体的简单属性和单向关联数据进行脏数据检查
  • 它通过删除数据库快照来节约内存

如何使持久化对象只读

只有持久化对象才能成为只读类型。瞬时态和游离态的对象在转化成只读状态之前必须成为持久化状态。

NHibernate提供了下面的几种方法让持久化对象成为只读类型:

  • 你可以将实体类型映射成不变类型,当一个不变类变成持久化状态的时候,NHibernate会自动将它变成只读类型。
  • 你可以改变默认值,因此实体在加载到这个session中的时候会自动转化成只读类型。
  • 你可以让一个HQL查询或者条件查询只读,因此当这个HQL或者条件查询执行,或者遍历的时候,都会自动变成只读类型。
  • 你可以让一个session中的持久化实体只读。

不可变类型实体

当一个不变类实体实例转化成持久化状态的时候,NHibernate会自动让它变成只读类型。

一个不可变类可以像一个可变类一样新增和删除。

NHibernate对待一个不可变类型的持久化实体和不可变实体的只读持久化类型是一样的。唯一的不同是NHibernate不允许不可变类实体改变,即使它不是只读类型。(吐槽:真搞不懂,整个文档一直颠来倒去地重复说这句话有什么意义)

将持久化对象加载成只读类型的

注意

不可变类会被自动加载成只读类型。

要改变NHibernate加载不可变类型的时候自动将它转化成只读的默认行为,调用:

Session.DefaultReadOnly = true;

想要改变回去,调用

Session.DefaultReadOnly = false;

你可以通过使用这属性来决定当前的设定

Session.DefaultReadOnly;

如果Session.DefaultReadOnly 属性返回true,被下面方法加载的实体会自动变成只读类型:

If Session.DefaultReadOnly property returns true, entities loaded by the following are automatically made read-only:

  • Session.Load()Session.Load<T>

  • Session.Get() 吧、和 Session.Get<T>

  • Session.Merge()

  • Changing this default has no effect on:改变这个默认值不会对下面实体产生影响:

  • persistent entities already in the session when the default was changed默认配置改变的时候已经在session中的持久化实体

  • persistent entities that are refreshed via Session.Refresh(); a refreshed persistent entity will only be read-only if it as read-only before refreshing通过Session.Refresh()刷新的持久化实体;一个已经被刷新的持久化实体将只会是只读的,如果在它刷新之前是只读的

  • persistent entities added by the application via Session.Persist(), Session.Save(), and Session.Update()Session.SaveOrUpdate()应用程序通过Session.Persist(), Session.Save()Session.Update() 或者 Session.SaveOrUpdate()添加的持久化实体。

通过HQL/条件查询来加载只读实体(不推荐使用HQL和criteria)

Note

Entities of immutable classes are automatically loaded as read-only.

If Session.DefaultReadOnly returns false (the default) when an HQL query or criteria executes, then entities and proxies of mutable classes loaded by the query will not be read-only.

You can override this behavior so that entities and proxies loaded by an HQL query or criteria are automatically made read-only.

For an HQL query, call:

Query.SetReadOnly(true);

Query.SetReadOnly(true) must be called before Query.List(), Query.UniqueResult(), or Query.Iterate()

For an HQL criteria, call:

Criteria.SetReadOnly(true);

Criteria.SetReadOnly(true) must be called before Criteria.List(), or Criteria.UniqueResult()

Entities and proxies that exist in the session before being returned by an HQL query or criteria are not affected.

Uninitialized persistent collections returned by the query are not affected. Later, when the collection is initialized, entities loaded into the session will be read-only if Session.DefaultReadOnly returns true.

Using Query.SetReadOnly(true) or Criteria.SetReadOnly(true) works well when a single HQL query or criteria loads all the entities and intializes all the proxies and collections that the application needs to be read-only.

When it is not possible to load and initialize all necessary entities in a single query or criteria, you can temporarily change the session default to load entities as read-only before the query is executed. Then you can explicitly initialize proxies and collections before restoring the session default.

ISession session = factory.OpenSession();
ITransaction tx = session.BeginTransaction(); session.DefaultReadOnly = true;
Contract contract = session.CreateQuery("from Contract where CustomerName = 'Sherman'").UniqueResult<Contract>();
NHibernate.Initialize(contract.Plan);
NHibernate.Initialize(contract.Variations);
NHibernate.Initialize(contract.Notes);
session.DefaultReadOnly = false;
...
tx.Commit();
session.Close();

If Session.DefaultReadOnly returns true, then you can use Query.SetReadOnly(false) and Criteria.SetReadOnly(false) to override this session setting and load entities that are not read-only.

让一个实体变成只读类型

想要让一个持久化实体或者代理只读,调用

To make a persistent entity or proxy read-only, call:

Session.SetReadOnly(entityOrProxy, true)

要改变一个不可变类型的只读实体或代理来让它不是只读的,调用

To change a read-only entity or proxy of a mutable class so it is no longer read-only, call:

Session.SetReadOnly(entityOrProxy, false)

重要

当一个只读实体或者代理改变成不是只读的时候,NHibernate会假设只读实体的状态和它的字段是一致的。如果不是这样的话,任何在之前或者在改变状态的时候还没有flush的改变,都会被忽略。

要抛弃未flush的改变,让持久化实体的状态和字段一致,调用:

When a read-only entity or proxy is changed so it is no longer read-only, NHibernate assumes that the current state of the read-only entity is consistent with its database representation. If this is not true, then any non-flushed changes made before or while the entity was read-only, will be ignored.

To throw away non-flushed changes and make the persistent entity consistent with its database representation, call:

Session.Refresh(entity);

想要flush在之前或者在改变状态的时候的改变,然后和数据库一致:

To flush changes made before or while the entity was read-only and make the database representation consistent with the current state of the persistent entity:

// evict the read-only entity so it is detached
session.Evict(entity); // make the detached entity (with the non-flushed changes) persistent
session.Update(entity); // now entity is no longer read-only and its changes can be flushed
s.Flush();

Read-only affect on property type只读类型对属性类型的影响

下面的表格总结了使一个实体变成只读状态之后不同属性类型会受到怎样的影响:

The following table summarizes how different property types are affected by making an entity read-only.

Table Affect of read-only entity on property types

属性/关联对象类型 flush之后是否会改变

简单属性

单向的一对一

单向的多对一


单向的一对多

单向的多对多


双向的一对一 仅仅在实体不是只读的时候会改变

双向的一对多/多对一

集合反向

集合非反向

仅仅添加/删除非只读类型实体的时候会改变
双向的多对多

*当实体包含只读属性或者关联对象的时候是不一样的。

简单属性

当一个持久化实体是只读的时候,Nhibernate不会对简单属性进行脏检查(dirty-check )。

NHibernate不会同步简单属性的状态到数据库中。如果你使用了自动版本控制,Nhibernate不会更新版本信息。

When a persistent object is read-only, NHibernate does not dirty-check simple properties.

NHibernate will not synchronize simple property state changes to the database. If you have automatic versioning, NHibernate will not increment the version if any simple properties change.

ISession session = factory.OpenSession();
ITransaction tx = session.BeginTransaction(); // get a contract and make it read-only
Contract contract = session.Get<Contract>(contractId);
session.SetReadOnly(contract, true); // contract.CustomerName is "Sherman"
contract.CustomerName = "Yogi";
tx.Commit(); tx = session.BeginTransaction(); contract = session.Get<Contract>(contractId);
// contract.CustomerName is still "Sherman"
...
tx.Commit();
session.Close();

Unidirectional associations

Unidirectional one-to-one and many-to-one

当包含只读实体的时候,Nhibernate处理单向的一对一和多对一关联是相同的。

当讨论单方向的一对一和多对一关联的时候,我们会使用我们使用无方向的单向这个名词。

当包含只读实体的时候,Nhibernate不会对单向的关联进行脏检查。

如果你把只读实体的关联从单向关联变为null,或者变成其他实体,flush之后改变不会提交到数据库。

注意

如果一个不可变实体引用一个单向实体,它必须因为实体会自动被设置成只读,这些引用都不会被更新。

如果使用了自动版本控制,Nhibernate不会把单向关联的版本信息更新。

在下面的例子中,Contract有一个单向的多对一的Plan关联。Contract会级联保存和更新它的关联实体。

下面的例子战士了改变一个只读的多对一关系到null并不会影响实体数据库的信息。

NHibernate treats unidirectional one-to-one and many-to-one associations in the same way when the owning entity is read-only.

We use the term unidirectional single-ended association when referring to functionality that is common to unidirectional one-to-one and many-to-one associations.

NHibernate does not dirty-check unidirectional single-ended associations when the owning entity is read-only.

If you change a read-only entity's reference to a unidirectional single-ended association to null, or to refer to a different entity, that change will not be flushed to the database.

Note

If an entity is of an immutable class, then its references to unidirectional single-ended associations must be assigned when that entity is first created. Because the entity is automatically made read-only, these references can not be updated.

If automatic versioning is used, NHibernate will not increment the version due to local changes to unidirectional single-ended associations.

In the following examples, Contract has a unidirectional many-to-one association with Plan. Contract cascades save and update operations to the association.

The following shows that changing a read-only entity's many-to-one association reference to null has no effect on the entity's database representation.

// get a contract with an existing plan;
// make the contract read-only and set its plan to null
tx = session.BeginTransaction();
Contract contract = session.Get<Contract>(contractId);
session.SetReadOnly(contract, true);
contract.Plan = null;
tx.Commit(); // get the same contract
tx = session.BeginTransaction();
Contract contract = session.Get<Contract>(contractId); // contract.Plan still refers to the original plan; tx.Commit();
session.Close();

The following shows that, even though an update to a read-only entity's many-to-one association has no affect on the entity's database representation, flush still cascades the save-update operation to the locally changed association.

下面的例子展示了,尽管一个对只读实体多对一关联的更新不会影响实体的数据库信息,flush操作仍然会级联执行本地关联的save-update操作。

// get a contract with an existing plan;
// make the contract read-only and change to a new plan
tx = session.BeginTransaction();
Contract contract = session.Get<Contract>(contractId);
session.SetReadOnly(contract, true);
Plan newPlan = new Plan("new plan");
contract.Plan = newPlan;
tx.Commit(); // get the same contract
tx = session.BeginTransaction();
contract = session.Get<Contract>(contractId);
newPlan = session.Get<Plan>(newPlan.Id); // contract.Plan still refers to the original plan;
// newPlan is non-null because it was persisted when
// the previous transaction was committed; tx.Commit();
session.Close();

Unidirectional one-to-many and many-to-many

NHibernate treats unidirectional one-to-many and many-to-many associations owned by a read-only entity the same as when owned by an entity that is not read-only.

NHibernate dirty-checks unidirectional one-to-many and many-to-many associations;

The collection can contain entities that are read-only, as well as entities that are not read-only.

Entities can be added and removed from the collection; changes are flushed to the database.

If automatic versioning is used, NHibernate will update the version due to changes in the collection if they dirty the owning entity.

当包含只读实体的时候,Nhibernate处理单向的一对多和多对多关联是相同的。

NHibernate会对单向的一对多和多对对关系进行脏检查。

集合可以包含只读实体,它们的改变会被flush操作提交到数据库。

如果使用了自动版本机制,Nhibernate会在修改提交后更新版本信息。

Bidirectional associations

Bidirectional one-to-one

如果一个只读实体包含了双向的一对一关联:

  • NHibernate不会对关系进行脏检查
  • 将关联引用到null或者其他的实体类型的修改操作不会被flush到数据库中
  • 如果使用了自动版本功能,NHibernate不会因为本地数据的改变而更新版本信息

注意

如果一个实体是不可变类型,并且它包含双向的一对一关联,当这个实体第一次被创建的时候,它的引用必须被assigned。因为这个实体会自动变成只读的,而这些引用不能被更新。

当所有者不是只读的时候,NHibernate处理只读实体关联和非只读实体关联是一样的。

If a read-only entity owns a bidirectional one-to-one association:

  • NHibernate does not dirty-check the association.

  • updates that change the association reference to null or to refer to a different entity will not be flushed to the database.

  • If automatic versioning is used, NHibernate will not increment the version due to local changes to the association.

Note

If an entity is of an immutable class, and it owns a bidirectional one-to-one association, then its reference must be assigned when that entity is first created. Because the entity is automatically made read-only, these references cannot be updated.

When the owner is not read-only, NHibernate treats an association with a read-only entity the same as when the association is with an entity that is not read-only.

Bidirectional one-to-many/many-to-one

一个只读实体不会影响双向多对一/一对多关联,如果:

  • 只读实体在一对多的一端并且使用反转集合
  • 只读实体在一对多的一端并且不使用反转集合
  • 一对多一段使用非反转集合并且包含只读实体
  • 当一对多端使用一个反转集合
  • 一个只读实体只能在集合生成的时候添加进去
  • 一个只读实体只能怪通过显示的孤儿删除方式来移除出集合

A read-only entity has no impact on a bidirectional one-to-many/many-to-one association if:

  • the read-only entity is on the one-to-many side using an inverse collection;

  • the read-only entity is on the one-to-many side using a non-inverse collection;

  • the one-to-many side uses a non-inverse collection that contains the read-only entity

  • When the one-to-many side uses an inverse collection:

  • a read-only entity can only be added to the collection when it is created;

  • a read-only entity can only be removed from the collection by an orphan delete or by explicitly deleting the entity.

Bidirectional many-to-many

双向多对多

当包含只读实体的时候,Nhibernate处理双向的多对多关联是相同的。

NHibernate会对双向的多对多和多对对关系进行脏检查。

集合无论在哪端都可以包含只读实体和费只读实体。

实体可以从任意端添加或者删除,这些改变都会通过flush操作提交到数据库。

如果使用了自动版本机制,对于来自任意一端的修改,Nhibernate会在修改提交后更新版本信息。

NHibernate treats bidirectional many-to-many associations owned by a read-only entity the same as when owned by an entity that is not read-only.

NHibernate dirty-checks bidirectional many-to-many associations.

The collection on either side of the association can contain entities that are read-only, as well as entities that are not read-only.

Entities are added and removed from both sides of the collection; changes are flushed to the database.

If automatic versioning is used, NHibernate will update the version due to changes in both sides of the collection if they dirty the entity owning the respective collections.

NHibernate官方文档中文版--只读实体类型(Read-only entities)的更多相关文章

  1. NHibernate官方文档中文版——持久化类(Persistent Classes)

    持久化类是一个应用程序中的类,主要用来实现业务逻辑(例如,在电商应用中的客户和订单类).持久化类,就像它的名字一样,生命周期短暂并且用来持久化的据库对象实例. 如果这些类的构造能够依照一些简单的原则, ...

  2. NHibernate官方文档中文版--基础ORM(Basic O/R Mapping)

    映射声明 对象/关系映射在XML文件中配置.mapping文件这样设计是为了使它可读性强并且可修改.mapping语言是以对象为中心,意味着mapping是围绕着持久化类声明来建立的,而不是围绕数据表 ...

  3. NHibernate官方文档中文版——批量插入(Batch inserts)

    A naive approach t7o inserting 100 000 rows in the database using NHibernate might look like this: 一 ...

  4. NHibernate官方文档中文版--ISessionFactory的配置(ISessionFactory Configuration)

    由于NHibernate是被设计应用在许多不同环境中的,因此它存在很多配置参数.幸运的是,这些参数大多都有合理的默认值,而且NHibernate发布的时候伴随着一个App.config 例子(可在sr ...

  5. NHibernate官方文档中文版——事务和并发(Transactions And Concurrency)

    NHibernate本身并不是一个数据库.它是一个轻量级的对象-关系映射工具.因此,它的事务管理代理给对应的数据库连接.如果这个连接代理了一个分布式的事务,ISession管理的操作就会自动成为整个分 ...

  6. NHibernate官方文档中文版--拦截器和事件(Interceptors and events)

    对于应用程序来说,能够对NHibernate内部发生的事件做出响应式很有用的.这能够有助于实现一些类的功能或者扩展NHibernate的功能. 拦截器 IInterceptor接口提供了应用程序ses ...

  7. NHibernate官方文档中文版-框架架构(Architecture)

    总体概览 一个非常高层次的NHibernate架构: 这个图展示了NHibernate使用数据库和配置信息来为应用程序提供持久化服务(和持久化对象). 我们想展示一个更加详细的运行时架构.但是NHib ...

  8. NHibernate官方文档——第八章 继承映射(Inheritance Mapping)

    本文翻译自NHibernate官方文档NHibernate Reference Documentation 4.1. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他 ...

  9. 人工智能系统Google开源的TensorFlow官方文档中文版

    人工智能系统Google开源的TensorFlow官方文档中文版 2015年11月9日,Google发布人工智能系统TensorFlow并宣布开源,机器学习作为人工智能的一种类型,可以让软件根据大量的 ...

随机推荐

  1. BigDecimal与Long、int之间的互换

    在实际开发过程中BigDecimal是一个经常用到的数据类型,它和int Long之间可以相互转换. 转换关系如下代码展示: int 转换成 BigDecimal 数据类型 //int 转换成 big ...

  2. 【HDU3853】LOOPS [期望DP]

    LOOPS Time Limit: 5 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description Akemi Homura is a ...

  3. 性能测试===Locust介绍

    简述性能测试 提起性能测试,可能移动APP的从业人员会感觉比较混淆,因为在客户端(Android.iOS)中也有性能测试专项,主要涉及的是APP的启动时间.内存.包大小.帧率,流量等客户端相关的指标. ...

  4. 冒泡排序的思想 python 冒泡排序、递归排序

    冒泡排序的时间复杂度是O(N^2) 冒泡排序的思想: 每次比较两个相邻的元素, 如果他们的顺序错误就把他们交换位置 比如有五个数: 12, 35, 99, 18, 76, 从大到小排序, 对相邻的两位 ...

  5. TCP的三次握手和四次挥手+TCP和UDP的区别

    TCP的三次握手: LISTEN:表示服务器端的某个socket处于监听状态,可以接收连接了. SYN_SENT:当客户端SOCKET执行connect连接时,它首先发送syn报文,随即会进入到此状态 ...

  6. MongoDB多集合排序的一种实现

    需求 假设有三个类型有所不同的表,saleorders.careorders.repairorders,表中有storeId信息,用于关联其所属的门店stores表,现在有个需求是要将这三个表集中展示 ...

  7. Android的简单应用(四)——字符串处理

    在Java中,对字符串进行处理的方法很多,也可以通过导入相应的字符串处理的lib包来进行处理.不过今天要说的是Android中看到的两种处理字符串的方法. 一.正则表达式 其实正则表达式没有大家想象的 ...

  8. eclipse启动几秒后报错 (一闪而过)

    eclipse启动报错,让查看.metadata/.log日志   1 !SESSION 2013-09-23 17:28:28.484 ------------------------------- ...

  9. 用IJ和gradle启动elasticsearch5.4.3

    环境准备 jdk gradle3.3+ idea git 从git clone源码 git checkout v5.4.3 打开项目 1. 在edit configurations添加new conf ...

  10. Android局域网访问webservice以及其中的一些问题

    应老师的要求,要做个安卓app,实现备份app上的数据到服务器上的mongodb上,网上搜了下相关的实现方式.利用webservice技术,具体来说就是客户端直接调用服务器端的接口.之前从来没接触这玩 ...