|
From: <jul...@us...> - 2011-02-24 17:11:15
|
Revision: 5397
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5397&view=rev
Author: julian-maughan
Date: 2011-02-24 17:11:05 +0000 (Thu, 24 Feb 2011)
Log Message:
-----------
Merged ReadOnlyEntities feature branch (r5306-5376, r5377-5396) into trunk.
Modified Paths:
--------------
trunk/nhibernate/doc/reference/master.xml
trunk/nhibernate/src/NHibernate/Engine/EntityEntry.cs
trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs
trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs
trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs
trunk/nhibernate/src/NHibernate/Engine/TwoPhaseLoad.cs
trunk/nhibernate/src/NHibernate/Event/Default/AbstractFlushingEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/AbstractReassociateEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/AbstractSaveEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultAutoFlushEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultEvictEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs
trunk/nhibernate/src/NHibernate/Event/Default/DefaultSaveOrUpdateEventListener.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs
trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs
trunk/nhibernate/src/NHibernate/Hql/IQueryTranslator.cs
trunk/nhibernate/src/NHibernate/ICriteria.cs
trunk/nhibernate/src/NHibernate/IQuery.cs
trunk/nhibernate/src/NHibernate/ISession.cs
trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs
trunk/nhibernate/src/NHibernate/Impl/CriteriaImpl.cs
trunk/nhibernate/src/NHibernate/Impl/EnumerableImpl.cs
trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs
trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs
trunk/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs
trunk/nhibernate/src/NHibernate/Loader/Loader.cs
trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
trunk/nhibernate/src/NHibernate/Proxy/AbstractLazyInitializer.cs
trunk/nhibernate/src/NHibernate/Proxy/ILazyInitializer.cs
trunk/nhibernate/src/NHibernate.Test/App.config
trunk/nhibernate/src/NHibernate.Test/Legacy/FooBarTest.cs
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1985/SampleTest.cs
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/doc/reference/modules/readonly.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/
trunk/nhibernate/src/NHibernate.Test/Immutable/Contract.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/ContractVariation.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/ContractVariation.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Contract.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/ContractVariation.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Info.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariation.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationVersioned.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationVersionedOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyFailureExpectedTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyJoinFailureExpectedTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariation.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationUnidir.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationVersioned.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationVersionedOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseManyToManyUnidirTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyUnidirTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Owner.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Party.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Plan.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/ImmutableTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/Info.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/Party.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/Plan.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/
trunk/nhibernate/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Container.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Course.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/DataPoint.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/DataPoint.hbm.xml
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Enrolment.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Enrolment.hbm.xml
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Info.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Owner.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyCriteriaQueryTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyProxyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlySessionLazyNonLazyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlySessionTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Student.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/StudentDto.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/TextHolder.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/TextHolder.hbm.xml
trunk/nhibernate/src/NHibernate.Test/ReadOnly/VersionedNode.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/VersionedNode.hbm.xml
Removed Paths:
-------------
trunk/nhibernate/src/NHibernate.Test/Immutable/Contract.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/ContractVariation.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/ContractVariation.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Contract.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/ContractVariation.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Info.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariation.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationVersioned.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationVersionedOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyFailureExpectedTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyJoinFailureExpectedTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariation.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationUnidir.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationVersioned.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationVersionedOneToManyJoin.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseManyToManyUnidirTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyUnidirTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseManyToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseOneToManyJoinTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseOneToManyTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Owner.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Party.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Plan.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/ImmutableTest.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/Info.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/Party.cs
trunk/nhibernate/src/NHibernate.Test/Immutable/Plan.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Container.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Course.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/DataPoint.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/DataPoint.hbm.xml
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Enrolment.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Enrolment.hbm.xml
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Info.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Owner.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyCriteriaQueryTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyProxyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlySessionLazyNonLazyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlySessionTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyTest.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/Student.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/StudentDto.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/TextHolder.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/TextHolder.hbm.xml
trunk/nhibernate/src/NHibernate.Test/ReadOnly/VersionedNode.cs
trunk/nhibernate/src/NHibernate.Test/ReadOnly/VersionedNode.hbm.xml
Modified: trunk/nhibernate/doc/reference/master.xml
===================================================================
--- trunk/nhibernate/doc/reference/master.xml 2011-02-24 14:37:45 UTC (rev 5396)
+++ trunk/nhibernate/doc/reference/master.xml 2011-02-24 17:11:05 UTC (rev 5397)
@@ -13,13 +13,14 @@
<!ENTITY manipulating-data SYSTEM "modules/manipulating_data.xml">
<!ENTITY transactions SYSTEM "modules/transactions.xml">
<!ENTITY events SYSTEM "modules/events.xml">
-<!ENTITY batch SYSTEM "modules/batch.xml">
+<!ENTITY batch SYSTEM "modules/batch.xml">
<!ENTITY query-hql SYSTEM "modules/query_hql.xml">
<!ENTITY query-criteria SYSTEM "modules/query_criteria.xml">
<!ENTITY query-queryover SYSTEM "modules/query_queryover.xml">
<!ENTITY query-sql SYSTEM "modules/query_sql.xml">
<!ENTITY filters SYSTEM "modules/filters.xml">
<!ENTITY performance SYSTEM "modules/performance.xml">
+<!ENTITY read-only SYSTEM "modules/readonly.xml">
<!ENTITY toolset-guide SYSTEM "modules/toolset_guide.xml">
<!ENTITY example-parentchild SYSTEM "modules/example_parentchild.xml">
<!ENTITY example-weblog SYSTEM "modules/example_weblog.xml">
@@ -38,7 +39,7 @@
<bookinfo>
<title>NHibernate - Relational Persistence for Idiomatic .NET</title>
<subtitle>NHibernate Reference Documentation</subtitle>
- <releaseinfo>3.0.0</releaseinfo>
+ <releaseinfo>3.0.1</releaseinfo>
</bookinfo>
<toc />
@@ -59,6 +60,7 @@
&inheritance-mapping;
&manipulating-data;
+ &read-only;
&transactions;
&events;
&batch;
Copied: trunk/nhibernate/doc/reference/modules/readonly.xml (from rev 5396, branches/ReadOnlyEntities/nhibernate/doc/reference/modules/readonly.xml)
===================================================================
--- trunk/nhibernate/doc/reference/modules/readonly.xml (rev 0)
+++ trunk/nhibernate/doc/reference/modules/readonly.xml 2011-02-24 17:11:05 UTC (rev 5397)
@@ -0,0 +1,823 @@
+<chapter id="readonly">
+ <title>Read-only entities</title>
+
+ <important>
+ <para>
+ NHibernate's treatment of <emphasis>read-only</emphasis> entities may
+ differ from what you may have encountered elsewhere. Incorrect usage
+ may cause unexpected results.
+ </para>
+ </important>
+
+ <para>
+ When an entity is read-only:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ NHibernate does not dirty-check the entity's simple
+ properties or single-ended associations;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ NHibernate will not update simple properties or updatable
+ single-ended associations;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ NHibernate will not update the version of the read-only
+ entity if only simple properties or single-ended
+ updatable associations are changed;
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ In some ways, NHibernate treats read-only entities the same as entities that are
+ not read-only:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ NHibernate cascades operations to associations as
+ defined in the entity mapping.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ NHibernate updates the version if the entity has a
+ collection with changes that dirties the entity;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A read-only entity can be deleted.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ Even if an entity is not read-only, its collection association can
+ be affected if it contains a read-only entity.
+ </para>
+
+ <para>
+ For details about the affect of read-only entities on different
+ property and association types, see
+ <xref linkend="readonly-proptypes"/>.
+ </para>
+
+ <para>
+ For details about how to make entities read-only, see
+ <xref linkend="readonly-api"/>
+ </para>
+
+ <para>
+ NHibernate does some optimizing for read-only entities:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ It saves execution time by not dirty-checking simple properties or
+ single-ended associations.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ It saves memory by deleting database snapshots.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <section id="readonly-api">
+ <title>Making persistent entities read-only</title>
+
+ <para>
+ Only persistent entities can be made read-only. Transient and
+ detached entities must be put in persistent state before they
+ can be made read-only.
+ </para>
+
+ <para>
+ NHibernate provides the following ways to make persistent entities read-only:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ you can map an entity class as <emphasis>immutable</emphasis>;
+ when an entity of an immutable class is made persistent,
+ NHibernate automatically makes it read-only.
+ see <xref linkend="readonly-api-immutable"/> for details
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ you can change a default so that entities loaded
+ into the session by NHibernate are automatically
+ made read-only; see <xref linkend="readonly-api-loaddefault"/> for details
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ you can make an HQL query or criteria read-only so
+ that entities loaded when the query or criteria executes,
+ or iterates, are automatically
+ made read-only; see <xref linkend="readonly-api-querycriteria"/> for details
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ you can make a persistent entity that is already in the
+ in the session read-only; see
+ <xref linkend="readonly-api-entity"/> for details
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <section id="readonly-api-immutable">
+ <title>Entities of immutable classes</title>
+
+ <para>
+ When an entity instance of an immutable class is made
+ persistent, NHibernate automatically makes it read-only.
+ </para>
+ <para>
+ An entity of an immutable class can created
+ and deleted the same as an entity of a mutable class.
+ </para>
+
+ <para>
+ NHibernate treats a persistent entity of an immutable
+ class the same way as a read-only persistent entity
+ of a mutable class. The only exception is that
+ NHibernate will not allow an entity of an immutable
+ class to be changed so it is not read-only.
+ </para>
+
+ </section>
+
+ <section id="readonly-api-loaddefault">
+ <title>Loading persistent entities as read-only</title>
+
+ <note>
+ <para>
+ Entities of immutable classes are automatically loaded
+ as read-only.
+ </para>
+ </note>
+
+ <para>
+ To change the default behavior so NHibernate loads entity
+ instances of mutable classes into the session and automatically
+ makes them read-only, call:
+ </para>
+ <programlisting role="c#">Session.DefaultReadOnly = true;</programlisting>
+
+ <para>
+ To change the default back so entities loaded by NHibernate are not
+ made read-only, call:
+ </para>
+ <programlisting role="c#">Session.DefaultReadOnly = false;</programlisting>
+
+ <para>
+ You can determine the current setting by using the property:
+ </para>
+ <programlisting role="c#">Session.DefaultReadOnly;</programlisting>
+
+ <para>
+ If Session.DefaultReadOnly property returns true, entities loaded by
+ the following are automatically made read-only:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Session.Load() and Session.Load<T>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Session.Get() and Session.Get<T>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Session.Merge()
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ executing, or iterating HQL queries and
+ criteria; to override this setting for a particular
+ HQL query or criteria see
+ <xref linkend="readonly-api-querycriteria"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Changing this default has no effect on:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ persistent entities already in the session when the
+ default was changed
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ persistent entities that are refreshed via
+ Session.Refresh(); a refreshed persistent
+ entity will only be read-only if it was
+ read-only before refreshing
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ persistent entities added by the application via
+ Session.Persist(), Session.Save(), and Session.Update()
+ Session.SaveOrUpdate()
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </section>
+
+ <section id="readonly-api-querycriteria">
+ <title>Loading read-only entities from an HQL query/criteria</title>
+
+ <note>
+ <para>
+ Entities of immutable classes are automatically loaded
+ as read-only.
+ </para>
+ </note>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ You can override this behavior so that entities and proxies loaded
+ by an HQL query or criteria are automatically made read-only.
+ </para>
+
+ <para>
+ For an HQL query, call:
+ </para>
+ <programlisting role="c#">Query.SetReadOnly(true);</programlisting>
+
+ <para>
+ <literal>Query.SetReadOnly(true)</literal> must be called before
+ <literal>Query.List()</literal>, <literal>Query.UniqueResult()</literal>, or <literal>Query.Iterate()</literal>
+ </para>
+
+ <para>
+ For an HQL criteria, call:
+ </para>
+ <programlisting role="c#">Criteria.SetReadOnly(true);</programlisting>
+
+ <para>
+ <literal>Criteria.SetReadOnly(true)</literal> must be called before
+ <literal>Criteria.List()</literal>, or <literal>Criteria.UniqueResult()</literal>
+ </para>
+
+ <para>
+ Entities and proxies that exist in the session before being returned
+ by an HQL query or criteria are not affected.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ Using <literal>Query.SetReadOnly(true)</literal> or
+ <literal>Criteria.SetReadOnly(true)</literal> 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.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <programlisting role="c#">
+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();
+
+</programlisting>
+
+ <para>
+ 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.
+ </para>
+
+ </section>
+
+ <section id="readonly-api-entity">
+ <title>Making a persistent entity read-only</title>
+ <note>
+ <para>
+ Persistent entities of immutable classes are automatically
+ made read-only.
+ </para>
+ </note>
+
+ <para>
+ To make a persistent entity or proxy read-only, call:
+ </para>
+ <programlisting>Session.SetReadOnly(entityOrProxy, true)</programlisting>
+
+ <para>
+ To change a read-only entity or proxy of a mutable class so
+ it is no longer read-only, call:
+ </para>
+ <programlisting>Session.SetReadOnly(entityOrProxy, false)</programlisting>
+
+ <important>
+ <para>
+ 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.
+ </para>
+ </important>
+
+ <para>
+ To throw away non-flushed changes and make the persistent entity
+ consistent with its database representation, call:
+ </para>
+ <programlisting role="c#">Session.Refresh(entity);</programlisting>
+
+ <para>
+ 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:
+ </para>
+<programlisting role="c#">
+// 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();
+</programlisting>
+ </section>
+ </section>
+
+ <section id="readonly-proptypes">
+ <title>Read-only affect on property type</title>
+
+ <para>
+ The following table summarizes how different property types are
+ affected by making an entity read-only.
+ </para>
+
+ <table frame="topbot" id="readonly-proptype-summary">
+ <title>Affect of read-only entity on property types</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property/Association Type</entry>
+ <entry>Changes flushed to DB?</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ Simple
+ <para>
+ (<xref linkend="readonly-proptypes-simple"/>)
+ </para>
+ </entry>
+ <entry>no*</entry>
+ </row>
+ <row>
+ <entry>
+ <para>Unidirectional one-to-one</para>
+ <para>Unidirectional many-to-one</para>
+ <para>
+ (<xref linkend="readonly-proptypes-singleended-unidir"/>)
+ </para>
+ </entry>
+
+ <entry>
+ <para>no*</para>
+ <para>no*</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>Unidirectional one-to-many</para>
+ <para>Unidirectional many-to-many</para>
+ <para>
+ (<xref linkend="readonly-proptypes-manyended-unidir"/>)
+ </para>
+ </entry>
+ <entry>
+ <para>yes</para>
+ <para>yes</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>Bidirectional one-to-one</para>
+ <para>
+ (<xref linkend="readonly-proptypes-onetoone-bidir"/>)
+ </para>
+ </entry>
+ <entry>only if the owning entity is not read-only*</entry>
+ </row>
+ <row>
+ <entry>
+ <para>Bidirectional one-to-many/many-to-one</para>
+ <para>inverse collection</para>
+ <para>non-inverse collection</para>
+ <para>
+ (<xref linkend="readonly-proptypes-onetomany-manytoone"/>)
+ </para>
+ </entry>
+ <entry>
+ <para> </para>
+ <para>only added/removed entities that are not read-only*</para>
+ <para>yes</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>Bidirectional many-to-many</para>
+ <para>
+ (<xref linkend="readonly-proptypes-manytomany-bidir"/>)
+ </para>
+ </entry>
+ <entry>yes</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ * Behavior is different when the entity having the property/association
+ is read-only, compared to when it is not read-only.
+ </para>
+
+ <section id="readonly-proptypes-simple">
+ <title>Simple properties</title>
+
+ <para>
+ When a persistent object is read-only, NHibernate does not
+ dirty-check simple properties.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <programlisting role="c#">
+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();
+ </programlisting>
+
+ </section>
+
+ <section id="readonly-prop-types-unidir">
+ <title>Unidirectional associations</title>
+
+ <section id="readonly-proptypes-singleended-unidir">
+ <title>Unidirectional one-to-one and many-to-one</title>
+
+ <para>
+ NHibernate treats unidirectional one-to-one and many-to-one
+ associations in the same way when the owning entity is
+ read-only.
+ </para>
+
+ <para>
+ We use the term <emphasis>unidirectional single-ended
+ association</emphasis> when referring to functionality
+ that is common to unidirectional one-to-one and many-to-one
+ associations.
+ </para>
+
+ <para>
+ NHibernate does not dirty-check unidirectional single-ended
+ associations when the owning entity is read-only.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <note>
+ <para>
+ 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.
+ </para>
+ </note>
+
+ <para>
+ If automatic versioning is used, NHibernate will not
+ increment the version due to local changes to
+ unidirectional single-ended associations.
+ </para>
+
+ <para>
+ In the following examples, Contract has a unidirectional
+ many-to-one association with Plan. Contract cascades save and
+ update operations to the association.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+<programlisting role="c#">// 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();</programlisting>
+
+ <para>
+ 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.
+ </para>
+
+<programlisting role="c#">// 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();</programlisting>
+
+ </section>
+
+ <section id="readonly-proptypes-manyended-unidir">
+ <title>Unidirectional one-to-many and many-to-many</title>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ NHibernate dirty-checks unidirectional one-to-many and
+ many-to-many associations;
+ </para>
+
+ <para>
+ The collection can contain entities that
+ are read-only, as well as entities
+ that are not read-only.
+ </para>
+
+ <para>
+ Entities can be added and removed from the
+ collection; changes are flushed to the database.
+ </para>
+
+ <para>
+ If automatic versioning is used, NHibernate will
+ update the version due to changes in the collection
+ if they dirty the owning entity.
+ </para>
+
+ </section>
+
+ </section>
+
+ <section id="readonly-proptypes-bidir">
+ <title>Bidirectional associations</title>
+
+ <section id="readonly-proptypes-onetoone-bidir">
+ <title>Bidirectional one-to-one</title>
+
+ <para>
+ If a read-only entity owns a bidirectional
+ one-to-one association:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ NHibernate does not dirty-check the association.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ updates that change the association reference
+ to null or to refer to a different entity
+ will not be flushed to the database.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If automatic versioning is used, NHibernate will not
+ increment the version due to local changes to
+ the association.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <note>
+ <para>
+ 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.
+ </para>
+ </note>
+
+ <para>
+ 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.
+ </para>
+
+ </section>
+
+ <section id="readonly-proptypes-onetomany-manytoone">
+ <title>Bidirectional one-to-many/many-to-one</title>
+
+ <para>
+ A read-only entity has no impact on a bidirectional
+ one-to-many/many-to-one association if:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ the read-only entity is on the one-to-many side
+ using an inverse collection;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the read-only entity is on the one-to-many side
+ using a non-inverse collection;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the one-to-many side uses a non-inverse collection
+ that contains the read-only entity
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ When the one-to-many side uses an inverse collection:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ a read-only entity can only be added to the collection
+ when it is created;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a read-only entity can only be removed from the
+ collection by an orphan delete or by explicitly
+ deleting the entity.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </section>
+
+ <section id="readonly-proptypes-manytomany-bidir">
+ <title>Bidirectional many-to-many</title>
+ <para>
+ 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.
+ </para>
+
+ <para>
+ NHibernate dirty-checks bidirectional many-to-many
+ associations.
+ </para>
+
+ <para>
+ The collection on either side of the association
+ can contain entities that are read-only, as well
+ as entities that are not read-only.
+ </para>
+
+ <para>
+ Entities are added and removed from both sides
+ of the collection; changes are flushed to the
+ database.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ </section>
+
+ </section>
+ </section>
+</chapter>
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Engine/EntityEntry.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/EntityEntry.cs 2011-02-24 14:37:45 UTC (rev 5396)
+++ trunk/nhibernate/src/NHibernate/Engine/EntityEntry.cs 2011-02-24 17:11:05 UTC (rev 5397)
@@ -14,6 +14,7 @@
{
private LockMode lockMode;
private Status status;
+ private Status? previousStatus;
private readonly object id;
private object[] loadedState;
private object[] deletedState;
@@ -21,10 +22,11 @@
private object version;
[NonSerialized]
- private IEntityPersister persister;// for convenience to save some lookups
+ private IEntityPersister persister; // for convenience to save some lookups
private readonly EntityMode entityMode;
private readonly string entityName;
+ private EntityKey cachedEntityKey;
private readonly bool isBeingReplicated;
private readonly bool loadedWithLazyPropertiesUnfetched;
@@ -50,9 +52,11 @@
bool disableVersionIncrement, bool lazyPropertiesAreUnfetched)
{
this.status = status;
- this.loadedState = loadedState;
+ this.previousStatus = null;
+ // only retain loaded state if the status is not Status.ReadOnly
+ if (status != Status.ReadOnly) { this.loadedState = loadedState; }
+ this.id = id;
this.rowId = rowId;
- this.id = id;
this.existsInDatabase = existsInDatabase;
this.version = version;
this.lockMode = lockMode;
@@ -74,7 +78,7 @@
}
/// <summary>
- /// Gets or sets the <see cref="Status"/> of this Entity with respect to its
+ /// Gets or sets the <see cref="Status"/> of this Entity with respect to its
/// persistence in the database.
/// </summary>
/// <value>The <see cref="Status"/> of this Entity.</value>
@@ -86,7 +90,11 @@
if (value == Status.ReadOnly)
loadedState = null; //memory optimization
- status = value;
+ if (this.status != value)
+ {
+ previousStatus = this.status;
+ this.status = value;
+ }
}
}
@@ -94,7 +102,7 @@
/// Gets or sets the identifier of the Entity in the database.
/// </summary>
/// <value>The identifier of the Entity in the database if one has been assigned.</value>
- /// <remarks>This might be <see langword="null" /> when the <see cref="EntityEntry.Status"/> is
+ /// <remarks>This might be <see langword="null" /> when the <see cref="EntityEntry.Status"/> is
/// <see cref="Engine.Status.Saving"/> and the database generates the id.</remarks>
public object Id
{
@@ -129,7 +137,7 @@
/// </summary>
/// <value><see langword="true" /> if it is already in the database.</value>
/// <remarks>
- /// It can also be <see langword="true" /> if it does not exists in the database yet and the
+ /// It can also be <see langword="true" /> if it does not exists in the database yet and the
/// <see cref="IEntityPersister.IsIdentifierAssignedByInsert"/> is <see langword="true" />.
/// </remarks>
public bool ExistsInDatabase
@@ -179,15 +187,33 @@
{
get { return loadedWithLazyPropertiesUnfetched; }
}
+
+ /// <summary>
+ /// Get the EntityKey based on this EntityEntry.
+ /// </summary>
+ public EntityKey EntityKey
+ {
+ get
+ {
+ if (cachedEntityKey == null)
+ {
+ if (id == null)
+ throw new InvalidOperationException("cannot generate an EntityKey when id is null.");
+ cachedEntityKey = new EntityKey(id, persister, entityMode);
+ }
+ return cachedEntityKey;
+ }
+ }
+
public object GetLoadedValue(string propertyName)
{
int propertyIndex = ((IUniqueKeyLoadable) persister).GetPropertyIndex(propertyName);
return loadedState[propertyIndex];
}
- /// <summary>
- /// After actually inserting a row, record the fact that the instance exists on the
+ /// <summary>
+ /// After actually inserting a row, record the fact that the instance exists on the
/// database (needed for identity-column key generation)
/// </summary>
public void PostInsert()
@@ -213,12 +239,13 @@
FieldInterceptionHelper.ClearDirty(entity);
}
- /// <summary>
+ /// <summary>
/// After actually deleting a row, record the fact that the instance no longer
/// exists in the database
/// </summary>
public void PostDelete()
{
+ previousStatus = status;
status = Status.Gone;
existsInDatabase = false;
}
@@ -230,7 +257,7 @@
LockMode = LockMode.Force;
persister.SetPropertyValue(entity, Persister.VersionProperty, nextVersion, entityMode);
}
-
+
public bool IsNullifiable(bool earlyInsert, ISessionImplementor session)
{
return Status == Status.Saving || (earlyInsert ? !ExistsInDatabase : session.PersistenceContext.NullifiableEntityKeys.Contains(new EntityKey(Id, Persister, entityMode)));
@@ -238,21 +265,42 @@
public bool RequiresDirtyCheck(object entity)
{
- bool isMutableInstance = status != Status.ReadOnly && persister.IsMutable;
-
return
- isMutableInstance
- &&
- (Persister.HasMutableProperties || !FieldInterceptionHelper.IsInstrumented(entity)
- || FieldInterceptionHelper.ExtractFieldInterceptor(entity).IsDirty);
+ IsModifiableEntity()
+ && (Persister.HasMutableProperties || !FieldInterceptionHelper.IsInstrumented(entity)
+ || FieldInterceptionHelper.ExtractFieldInterceptor(entity).IsDirty);
}
+
+ /// <summary>
+ /// Can the entity be modified?
+ /// The entity is modifiable if all of the following are true:
+ /// - the entity class is mutable
+ /// - the entity is not read-only
+ /// - if the current status is Status.Deleted, then the entity was not read-only when it was deleted
+ /// </summary>
+ /// <returns>true, if the entity is modifiable; false, otherwise</returns>
+ public bool IsModifiableEntity()
+ {
+ return (status != Status.ReadOnly) && !(status == Status.Deleted && previousStatus == Status.ReadOnly) && Persister.IsMutable;
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ if (status != Status.Loaded && status != Status.ReadOnly)
+ {
+ throw new HibernateException("instance was not in a valid state");
+ }
+ return status == Status.ReadOnly;
+ }
+ }
public void SetReadOnly(bool readOnly, object entity)
{
- if (status != Status.Loaded && status != Status.ReadOnly)
- {
- throw new HibernateException("instance was not in a valid state");
- }
+ if (readOnly == IsReadOnly)
+ return; // simply return since the status is not being changed
+
if (readOnly)
{
Status = Status.ReadOnly;
@@ -260,6 +308,9 @@
}
else
{
+ if (!persister.IsMutable)
+ throw new InvalidOperationException("Cannot make an immutable entity modifiable.");
+
Status = Status.Loaded;
loadedState = Persister.GetPropertyValues(entity, entityMode);
}
Modified: trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2011-02-24 14:37:45 UTC (rev 5396)
+++ trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2011-02-24 17:11:05 UTC (rev 5397)
@@ -9,25 +9,25 @@
namespace NHibernate.Engine
{
- /// <summary>
- /// Holds the state of the persistence context, including the
- /// first-level cache, entries, snapshots, proxies, etc.
+ /// <summary>
+ /// Holds the state of the persistence context, including the
+ /// first-level cache, entries, snapshots, proxies, etc.
/// </summary>
public interface IPersistenceContext
{
bool IsStateless { get;}
- /// <summary>
- /// Get the session to which this persistence context is bound.
+ /// <summary>
+ /// Get the session to which this persistence context is bound.
/// </summary>
ISessionImplementor Session { get;}
- /// <summary>
+ /// <summary>
/// Retrieve this persistence context's managed load context.
/// </summary>
LoadContexts LoadContexts { get;}
- /// <summary>
+ /// <summary>
/// Get the <tt>BatchFetchQueue</tt>, instantiating one if necessary.
/// </summary>
BatchFetchQueue BatchFetchQueue { get;}
@@ -52,12 +52,30 @@
/// <summary>Is a flush cycle currently in process?</summary>
/// <remarks>Called before and after the flushcycle</remarks>
- bool Flushing { get;set;}
+ bool Flushing { get; set;}
+
+ /// <summary>
+ /// The read-only status for entities (and proxies) loaded into this persistence context.
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// When a proxy is initialized, the loaded entity will have the same read-only
+ /// setting as the uninitialized proxy has, regardless of the persistence context's
+ /// current setting.
+ /// </para>
+ /// <para>
+ /// To change the read-only setting for a particular entity or proxy that is already
+ /// in the current persistence context, use <see cref="IPersistenceContext.SetReadOnly(object, bool)" />.
+ /// </para>
+ /// </remarks>
+ /// <seealso cref="IPersistenceContext.IsReadOnly(object)" />
+ /// <seealso cref="IPersistenceContext.SetReadOnly(object, bool)" />
+ bool DefaultReadOnly { get; set; }
/// <summary> Add a collection which has no owner loaded</summary>
void AddUnownedCollection(CollectionKey key, IPersistentCollection collection);
- /// <summary>
+ /// <summary>
/// Get and remove a collection whose owner is not yet loaded,
/// when its owner is being loaded
/// </summary>
@@ -75,13 +93,13 @@
/// <summary> Called after transactions end</summary>
void AfterTransactionCompletion();
- /// <summary>
+ /// <summary>
/// Get the current state of the entity as known to the underlying
- /// database, or null if there is no corresponding row
+ /// database, or null if there is no corresponding row
/// </summary>
object[] GetDatabaseSnapshot(object id, IEntityPersister persister);
- /// <summary>
+ /// <summary>
/// Retrieve the cached database snapshot for the requested entity key.
/// </summary>
/// <param name="key">The entity key for which to retrieve the cached snapshot </param>
@@ -95,9 +113,9 @@
/// </remarks>
object[] GetCachedDatabaseSnapshot(EntityKey key);
- /// <summary>
- /// Get the values of the natural id fields as known to the underlying
- /// database, or null if the entity has no natural id or there is no
+ /// <summary>
+ /// Get the values of the natural id fields as known to the underlying
+ /// database, or null if the entity has no natural id or there is no
/// corresponding row.
/// </summary>
object[] GetNaturalIdSnapshot(object id, IEntityPersister persister);
@@ -105,7 +123,7 @@
/// <summary> Add a canonical mapping from entity key to entity instance</summary>
void AddEntity(EntityKey key, object entity);
- /// <summary>
+ /// <summary>
/// Get the entity instance associated with the given <tt>EntityKey</tt>
/// </summary>
object GetEntity(EntityKey key);
@@ -113,7 +131,7 @@
/// <summary> Is there an entity with the given key in the persistence context</summary>
bool ContainsEntity(EntityKey key);
- /// <summary>
+ /// <summa...
[truncated message content] |