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] |