From: <jul...@us...> - 2011-02-11 14:44:39
|
Revision: 5379 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5379&view=rev Author: julian-maughan Date: 2011-02-11 14:44:33 +0000 (Fri, 11 Feb 2011) Log Message: ----------- Allow immutable objects to be deleted (ref. NH-1985) Modified Paths: -------------- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1985/SampleTest.cs Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs 2011-02-10 15:25:32 UTC (rev 5378) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs 2011-02-11 14:44:33 UTC (rev 5379) @@ -90,12 +90,6 @@ version = entityEntry.Version; } - if (!persister.IsMutable) - { - throw new HibernateException("Attempted to delete an object of immutable class: " - + MessageHelper.InfoString(persister)); - } - if (InvokeDeleteLifecycle(source, entity, persister)) { return; Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1985/SampleTest.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1985/SampleTest.cs 2011-02-10 15:25:32 UTC (rev 5378) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1985/SampleTest.cs 2011-02-11 14:44:33 UTC (rev 5379) @@ -26,6 +26,7 @@ } [Test] + [Ignore("It is valid to be delete immutable entities")] public void AttemptToDeleteImmutableObjectShouldThrow() { using (ISession session = OpenSession()) @@ -62,5 +63,43 @@ } } } + + [Test] + public void AllowDeletionOfImmutableObject() + { + using (ISession session = OpenSession()) + { + Assert.DoesNotThrow(() => + { + using (ITransaction trans = session.BeginTransaction()) + { + var entity = session.Get<DomainClass>(1); + session.Delete(entity); + + trans.Commit(); + } + }); + } + + using (IConnectionProvider prov = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + { + IDbConnection conn = prov.GetConnection(); + + try + { + using (IDbCommand comm = conn.CreateCommand()) + { + comm.CommandText = "SELECT Id FROM DomainClass WHERE Id=1 AND Label='TEST record'"; + object result = comm.ExecuteScalar(); + + Assert.That(result == null, "Immutable object has not been deleted!"); + } + } + finally + { + prov.CloseConnection(conn); + } + } + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jul...@us...> - 2011-02-11 16:07:48
|
Revision: 5380 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5380&view=rev Author: julian-maughan Date: 2011-02-11 16:07:38 +0000 (Fri, 11 Feb 2011) Log Message: ----------- Port of Hibernate read-only entities feature, including tests (NH-908) Modified Paths: -------------- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/EntityEntry.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/TwoPhaseLoad.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/AbstractFlushingEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/AbstractReassociateEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/AbstractSaveEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultAutoFlushEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultDeleteEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultEvictEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultFlushEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultReplicateEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Event/Default/DefaultSaveOrUpdateEventListener.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Hql/IQueryTranslator.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/ICriteria.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/IQuery.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/ISession.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/CriteriaImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/EnumerableImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/SessionImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Loader/Loader.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/AbstractLazyInitializer.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/ILazyInitializer.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Legacy/FooBarTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/ branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/Contract.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/ContractVariation.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/ContractVariation.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/ branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithOneToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Contract.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/ContractVariation.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Info.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariation.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationOneToManyJoin.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationVersioned.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/ContractVariationVersionedOneToManyJoin.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseManyToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseOneToManyJoinTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/EntityWithInverseOneToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseManyToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyFailureExpectedTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyJoinFailureExpectedTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyJoinTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Inverse/VersionedEntityWithInverseOneToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariation.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationOneToManyJoin.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationUnidir.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationVersioned.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/ContractVariationVersionedOneToManyJoin.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseManyToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseManyToManyUnidirTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyJoinTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/EntityWithNonInverseOneToManyUnidirTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseManyToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseOneToManyJoinTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/NonInverse/VersionedEntityWithNonInverseOneToManyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Owner.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Party.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/EntityWithMutableCollection/Plan.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/ImmutableTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/Info.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/Party.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/Immutable/Plan.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Container.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Course.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/DataPoint.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/DataPoint.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Enrolment.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Enrolment.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Info.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Owner.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyCriteriaQueryTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyProxyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlySessionLazyNonLazyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlySessionTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyTest.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/Student.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/StudentDto.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/TextHolder.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/TextHolder.hbm.xml branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/VersionedNode.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate.Test/ReadOnly/VersionedNode.hbm.xml Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/EntityEntry.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/EntityEntry.cs 2011-02-11 14:44:33 UTC (rev 5379) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/EntityEntry.cs 2011-02-11 16:07:38 UTC (rev 5380) @@ -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: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2011-02-11 14:44:33 UTC (rev 5379) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2011-02-11 16:07:38 UTC (rev 5380) @@ -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,47 @@ /// <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> + /// Change the default for entities and proxies loaded into this persistence + /// context from modifiable to read-only mode, or from modifiable to read-only + /// mode. + /// </summary> + /// <remarks> + /// <para> + /// Read-only entities are not dirty-checked and snapshots of persistent + /// state are not maintained. Read-only entities can be modified, but + /// changes are not persisted. + /// </para> + /// <para> + /// When a proxy is initialized, the loaded entity will have the same + /// read-only/modifiable setting as the uninitialized + /// proxy has, regardless of the persistence context's current setting. + /// </para> + /// <para> + /// To change the read-only/modifiable setting for a particular entity + /// or proxy that is already in this session: + /// <see cref="SetReadOnly(object, bool)" /> + /// <see cref="ISession.SetReadOnly(object, bool)" /> + /// </para> + /// <para> + /// To determine the read-only/modifiable setting for a particular entity or proxy: + /// <see cref="IsReadOnly(object)" /> + /// <see cref="ISession.IsReadOnly(object)" /> + /// </para> + /// <para> + /// To override this session's read-only/modifiable setting for entities + /// and proxies loaded by an IQuery: + /// <see cref="IQuery.SetReadOnly(bool)" /> + /// </para> + /// </remarks> + 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 +110,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 +130,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 +140,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 +148,7 @@ /// <summary> Is there an entity with the given key in the persistence context</summary> bool ContainsEntity(EntityKey key); - /// <summary> + /// <summary> /// Remove an entity from the session cache, also clear /// up other state associated with the entity, all except /// for the <tt>EntityEntry</tt> @@ -126,8 +161,8 @@ /// <summary> Add an entity to the cache by unique key</summary> void AddEntity(EntityUniqueKey euk, object entity); - /// <summary> - /// Retrieve the EntityEntry representation of the given entity. + /// <summary> + /// Retrieve the EntityEntry representation of the given entity. /// </summary> /// <param name="entity">The entity for which to locate the EntityEntry. </param> /// <returns> The EntityEntry for the given entity. </returns> @@ -147,8 +182,8 @@ LockMode lockMode, bool existsInDatabase, IEntityPersister persister, bool disableVersionIncrement, bool lazyPropertiesAreUnfetched); - /// <summary> - /// Generates an appropriate EntityEntry instance and adds it + /// <summary> + /// Generates an appropriate EntityEntry instance and adds it /// to the event source's internal caches. /// </summary> EntityEntry AddEntry(object entity, Status status, object[] loadedState, object rowId, object id, object version, @@ -161,34 +196,34 @@ /// <summary> Is the given proxy associated with this persistence context?</summary> bool ContainsProxy(INHibernateProxy proxy); - /// <summary> - /// Takes the given object and, if it represents a proxy, reassociates it with this event source. + /// <summary> + /// Takes the given object and, if it represents a proxy, reassociates it with this event source. /// </summary> /// <param name="value">The possible proxy to be reassociated. </param> /// <returns> Whether the passed value represented an actual proxy which got initialized. </returns> bool ReassociateIfUninitializedProxy(object value); - /// <summary> + /// <summary> /// If a deleted entity instance is re-saved, and it has a proxy, we need to - /// reset the identifier of the proxy + /// reset the identifier of the proxy /// </summary> void ReassociateProxy(object value, object id); - /// <summary> + /// <summary> /// Get the entity instance underlying the given proxy, throwing /// an exception if the proxy is uninitialized. If the given object /// is not a proxy, simply return the argument. /// </summary> object Unproxy(object maybeProxy); - /// <summary> - /// Possibly unproxy the given reference and reassociate it with the current session. + /// <summary> + /// Possibly unproxy the given reference and reassociate it with the current session. /// </summary> /// <param name="maybeProxy">The reference to be unproxied if it currently represents a proxy. </param> /// <returns> The unproxied instance. </returns> object UnproxyAndReassociate(object maybeProxy); - /// <summary> + /// <summary> /// Attempts to check whether the given key represents an entity already loaded within the /// current session. /// </summary> @@ -196,11 +231,11 @@ /// <param name="key">The entity key.</param> void CheckUniqueness(EntityKey key, object obj); - /// <summary> + /// <summary> /// If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy /// and overwrite the registration of the old one. This breaks == and occurs only for /// "class" proxies rather than "interface" proxies. Also init the proxy to point to - /// the given target implementation if necessary. + /// the given target implementation if necessary. /// </summary> /// <param name="proxy">The proxy instance to be narrowed. </param> /// <param name="persister">The persister for the proxied entity. </param> @@ -209,14 +244,14 @@ /// <returns> An appropriately narrowed instance. </returns> object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, EntityKey key, object obj); - /// <summary> + /// <summary> /// Return the existing proxy associated with the given <tt>EntityKey</tt>, or the /// third argument (the entity associated with the key) if no proxy exists. Init /// the proxy to the target implementation, if necessary. /// </summary> object ProxyFor(IEntityPersister persister, EntityKey key, object impl); - /// <summary> + /// <summary> /// Return the existing proxy associated with the given <tt>EntityKey</tt>, or the /// argument (the entity associated with the key) if no proxy exists. /// (slower than the form above) @@ -228,7 +263,7 @@ /// <summary> Get the entity that owned this persistent collection when it was loaded </summary> /// <param name="collection">The persistent collection </param> - /// <returns> + /// <returns> /// The owner if its entity ID is available from the collection's loaded key /// and the owner entity is in the persistence context; otherwise, returns null /// </returns> @@ -245,7 +280,7 @@ /// <summary> add a detached uninitialized collection</summary> void AddUninitializedDetachedCollection(ICollectionPersister persister, IPersistentCollection collection); - /// <summary> + /// <summary> /// Add a new collection (ie. a newly created one, just instantiated by the /// application, with no database state or snapshot) /// </summary> @@ -253,7 +288,7 @@ /// <param name="persister"></param> void AddNewCollection(ICollectionPersister persister, IPersistentCollection collection); - /// <summary> + /// <summary> /// add an (initialized) collection that was created by another session and passed /// into update() (ie. one with a snapshot and existing state on the database) /// </summary> @@ -265,12 +300,12 @@ /// <summary> Get the collection instance associated with the <tt>CollectionKey</tt></summary> IPersistentCollection GetCollection(CollectionKey collectionKey); - /// <summary> + /// <summary> /// Register a collection for non-lazy loading at the end of the two-phase load /// </summary> void AddNonLazyCollection(IPersistentCollection collection); - /// <summary> + /// <summary> /// Force initialization of all non-lazy collections encountered during /// the current two-phase load (actually, this is a no-op, unless this /// is the "outermost" load) @@ -281,12 +316,12 @@ IPersistentCollection GetCollectionHolder(object array); /// <summary> Register a <tt>PersistentCollection</tt> object for an array. - /// Associates a holder with an array - MUST be called after loading + /// Associates a holder with an array - MUST be called after loading /// array, since the array instance is not created until endLoad(). /// </summary> void AddCollectionHolder(IPersistentCollection holder); - /// <summary> + /// <summary> /// Remove the mapping of collection to holder during eviction of the owning entity /// </summary> IPersistentCollection RemoveCollectionHolder(object array); @@ -294,7 +329,7 @@ /// <summary> Get the snapshot of the pre-flush collection state</summary> object GetSnapshot(IPersistentCollection coll); - /// <summary> + /// <summary> /// Get the collection entry for a collection passed to filter, /// which might be a collection wrapper, an array, or an unwrapped /// collection. Return null if there is no entry. @@ -322,18 +357,18 @@ /// <summary> Call this after finishing a two-phase load</summary> void AfterLoad(); - /// <summary> + /// <summary> /// Search the persistence context for an owner for the child object, /// given a collection role /// </summary> object GetOwnerId(string entity, string property, object childObject, IDictionary mergeMap); - /// <summary> + /// <summary> /// Search the persistence context for an index of the child object, given a collection role /// </summary> object GetIndexInOwner(string entity, string property, object childObject, IDictionary mergeMap); - /// <summary> + /// <summary> /// Record the fact that the association belonging to the keyed entity is null. /// </summary> void AddNullProperty(EntityKey ownerKey, string propertyName); @@ -341,9 +376,56 @@ /// <summary> Is the association property belonging to the keyed entity null?</summary> bool IsPropertyNull(EntityKey ownerKey, string propertyName); - /// <summary> Set the object to read only and discard it's snapshot</summary> + /// <summary> + /// Set the entity or proxy to read only and discard it's snapshot. + /// Set an unmodified persistent object to read-only mode, or a read-only + /// object to modifiable mode. + /// </summary> + /// <remarks> + /// <para> + /// Read-only entities are not dirty-checked and snapshots of persistent + /// state are not maintained. Read-only entities can be modified, but + /// changes are not persisted. + /// </para> + /// <para> + /// When a proxy is initialized, the loaded entity will have the same + /// read-only/modifiable setting as the uninitialized + /// proxy has, regardless of the session's current setting. + /// </para> + /// <para> + /// If the entity or proxy already has the specified read-only/modifiable + /// setting, then this method does nothing. + /// </para> + /// <para> + /// To set the default read-only/modifiable setting used for + /// entities and proxies that are loaded into this persistence context: + /// <see cref="IPersistenceContext.DefaultReadOnly" /> + /// <see cref="ISession.DefaultReadOnly" /> + /// </para> + /// <para> + /// To override this persistence context's read-only/modifiable setting + /// for entities and proxies loaded by a Query: + /// <see cref="IQuery.SetReadOnly(bool)" /> + /// </para> + /// </remarks> + /// <param name="entity">An entity or INHibernateProxy</param> + /// <param name="readOnly">if <c>true</c>, the entity or proxy is made read-only; if <c>false</c>, the entity or proxy is made modifiable.</param> + /// <seealso cref="ISession.SetReadOnly(object, bool)" /> void SetReadOnly(object entity, bool readOnly); + /// <summary> + /// Is the entity or proxy read-only? + /// </summary> + /// <remarks> + /// To get the default read-only/modifiable setting used for + /// entities and proxies that are loaded into the session: + /// <see cref="ISession.DefaultReadOnly" /> + /// </remarks> + /// <returns> + /// <c>true</c>, the object is read-only; <c>false</c>, the object is modifiable. + /// </returns> + bool IsReadOnly(object entityOrProxy); + void ReplaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, object generatedId); } } Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2011-02-11 14:44:33 UTC (rev 5379) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2011-02-11 16:07:38 UTC (rev 5380) @@ -15,7 +15,7 @@ namespace NHibernate.Engine { /// <summary> - /// Container for data that is used during the NHibernate query/load process. + /// Container for data that is used during the NHibernate query/load process. /// </summary> [Serializable] public sealed class QueryParameters @@ -39,6 +39,7 @@ private object _optionalObject; private string _optionalEntityName; private object _optionalId; + private bool _isReadOnlyInitialized; private string _comment; private bool _readOnly; private int? limitParameterIndex = null; @@ -46,18 +47,14 @@ private IDictionary<int, int> _adjustedParameterLocations; private IDictionary<int, int> _tempPagingParameterIndexes; private IDictionary<int, int> _pagingParameterIndexMap; - private SqlString processedSQL; - private readonly IResultTransformer _resultTransformer; - // not implemented: private ScrollMode _scrollMode; - + public QueryParameters() : this(ArrayHelper.EmptyTypeArray, ArrayHelper.EmptyObjectArray) {} public QueryParameters(IType type, object value) : this(new[] {type}, new[] {value}) {} - public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, object optionalObject, - string optionalEntityName, object optionalObjectId) + public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, object optionalObject, string optionalEntityName, object optionalObjectId) : this(positionalParameterTypes, postionalParameterValues) { _optionalObject = optionalObject; @@ -66,32 +63,22 @@ } public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues) - : this(positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null, null) {} + : this(positionalParameterTypes, postionalParameterValues, null, null, false, false, false, null, null, false, null, null) {} public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, object[] collectionKeys) : this(positionalParameterTypes, postionalParameterValues, null, collectionKeys) {} - public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, - IDictionary<string, TypedValue> namedParameters, object[] collectionKeys) - : this( - positionalParameterTypes, postionalParameterValues, namedParameters, null, null, false, false, null, null, - collectionKeys, null) {} + public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, IDictionary<string, TypedValue> namedParameters, object[] collectionKeys) + : this(positionalParameterTypes, postionalParameterValues, namedParameters, null, null, false, false, false, null, null, collectionKeys, null) {} - public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, - IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool cacheable, - string cacheRegion, string comment, bool isLookupByNaturalKey, IResultTransformer transformer, IDictionary<int,int> tempPagingParameterIndexes) - : this( - positionalParameterTypes, positionalParameterValues, null, lockModes, rowSelection, false, cacheable, cacheRegion, - comment, null, transformer) + public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool isReadOnlyInitialized, bool readOnly, bool cacheable, string cacheRegion, string comment, bool isLookupByNaturalKey, IResultTransformer transformer, IDictionary<int,int> tempPagingParameterIndexes) + : this(positionalParameterTypes, positionalParameterValues, null, lockModes, rowSelection, isReadOnlyInitialized, readOnly, cacheable, cacheRegion, comment, null, transformer) { NaturalKeyLookup = isLookupByNaturalKey; _tempPagingParameterIndexes = tempPagingParameterIndexes; } - public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, - IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes, - RowSelection rowSelection, bool readOnly, bool cacheable, string cacheRegion, string comment, - object[] collectionKeys, IResultTransformer transformer) + public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool isReadOnlyInitialized, bool readOnly, bool cacheable, string cacheRegion, string comment, object[] collectionKeys, IResultTransformer transformer) { _positionalParameterTypes = positionalParameterTypes; _positionalParameterValues = positionalParameterValues; @@ -102,25 +89,19 @@ _cacheRegion = cacheRegion; _comment = comment; _collectionKeys = collectionKeys; + _isReadOnlyInitialized = isReadOnlyInitialized; _readOnly = readOnly; _resultTransformer = transformer; } - public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, - IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes, - RowSelection rowSelection, bool readOnly, bool cacheable, string cacheRegion, string comment, - object[] collectionKeys, object optionalObject, string optionalEntityName, object optionalId, - IResultTransformer transformer) - : this( - positionalParameterTypes, positionalParameterValues, namedParameters, lockModes, rowSelection, readOnly, cacheable, - cacheRegion, comment, collectionKeys, transformer) + public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues, IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool isReadOnlyInitialized, bool readOnly, bool cacheable, string cacheRegion, string comment, object[] collectionKeys, object optionalObject, string optionalEntityName, object optionalId, IResultTransformer transformer) + : this(positionalParameterTypes, positionalParameterValues, namedParameters, lockModes, rowSelection, isReadOnlyInitialized, readOnly, cacheable, cacheRegion, comment, collectionKeys, transformer) { _optionalEntityName = optionalEntityName; _optionalId = optionalId; _optionalObject = optionalObject; } - /// <summary></summary> public bool HasRowSelection { get { return _rowSelection != null; } @@ -136,9 +117,6 @@ get { return offsetParameterIndex; } } - /// <summary> - /// Named parameters. - /// </summary> public IDictionary<string, TypedValue> NamedParameters { get { return _namedParameters; } @@ -146,7 +124,7 @@ } /// <summary> - /// Gets or sets an array of <see cref="IType"/> objects that is stored at the index + /// Gets or sets an array of <see cref="IType"/> objects that is stored at the index /// of the Parameter. /// </summary> public IType[] PositionalParameterTypes @@ -161,7 +139,7 @@ } /// <summary> - /// Gets or sets an array of <see cref="object"/> objects that is stored at the index + /// Gets or sets an array of <see cref="object"/> objects that is stored at the index /// of the Parameter. /// </summary> public object[] PositionalParameterValues @@ -190,6 +168,19 @@ set { _lockModes = value; } } + /// <summary> + /// Has the read-only/modifiable mode been explicitly set? + /// </summary> + /// <value> + /// <c>true</c>, the read-only/modifiable mode was explicitly set; <c>false</c>, the read-only/modifiable mode was not explicitly set + /// </value> + /// <seealso cref="ReadOnly" /> + /// <seealso cref="IsReadOnly(ISessionImplementor)" /> + public bool IsReadOnlyInitialized + { + get { return _isReadOnlyInitialized; } + } + private void CreatePositionalParameterLocations(ISessionFactoryImplementor factory) { _positionalParameterLocations = new int[_positionalParameterTypes.Length]; @@ -211,7 +202,6 @@ return array.Length; } - /// <summary></summary> public void LogParameters(ISessionFactoryImplementor factory) { var print = new Printer(factory); @@ -248,7 +238,7 @@ /// Ensure the Types and Values are the same length. /// </summary> /// <exception cref="QueryException"> - /// If the Lengths of <see cref="PositionalParameterTypes"/> and + /// If the Lengths of <see cref="PositionalParameterTypes"/> and /// <see cref="PositionalParameterValues"/> are not equal. /// </exception> public void ValidateParameters() @@ -290,11 +280,30 @@ } public bool Callable { get; set; } - + + /// <summary> + /// Should entities and proxies loaded by the query be put in read-only mode? + /// </summary> + /// <remarks> + /// The read-only/modifiable setting has no impact on entities/proxies returned by the + /// query that existed in the session before the query was executed. + /// </remarks> + /// <seealso cref="IsReadOnlyInitialized" /> + /// <seealso cref="IsReadOnly(ISessionImplementor)" /> public bool ReadOnly { - get { return _readOnly; } - set { _readOnly = value; } + get + { + if (!_isReadOnlyInitialized) + throw new InvalidOperationException("cannot call ReadOnly when IsReadOnlyInitialized returns false"); + + return _readOnly; + } + set + { + _readOnly = value; + _isReadOnlyInitialized = true; + } } /************** Filters ********************************/ @@ -674,7 +683,7 @@ public QueryParameters CreateCopyUsing(RowSelection selection) { var copy = new QueryParameters(_positionalParameterTypes, _positionalParameterValues, _namedParameters, _lockModes, - selection, _readOnly, _cacheable, _cacheRegion, _comment, _collectionKeys, + selection, _isReadOnlyInitialized, _readOnly, _cacheable, _cacheRegion, _comment, _collectionKeys, _optionalObject, _optionalEntityName, _optionalId, _resultTransformer); copy._positionalParameterLocations = _positionalParameterLocations; copy.processedSQL = processedSQL; @@ -683,5 +692,27 @@ copy.filteredParameterLocations = filteredParameterLocations; return copy; } + + /// <summary> + /// Should entities and proxies loaded by the query be put in read-only mode? If the + /// read-only/modifiable setting was not initialized + /// (i.e. <see cref="IsReadOnlyInitialized" /> == false), then the default + /// read-only/modifiable setting for the persistence context is returned instead. + /// </summary> + /// <remarks> + /// The read-only/modifiable setting has no impact on entities/proxies returned by the + /// query that existed in the session before the query was executed. + /// </remarks> + /// <seealso cref="IsReadOnlyInitialized" /> + /// <seealso cref="ReadOnly" /> + /// <seealso cref="IPersistenceContext.DefaultReadOnly" /> + /// <param name="session"></param> + /// <returns> + /// <c>true</c>, entities and proxies loaded by the query will be put in read-only mode; <c>false</c>, entities and proxies loaded by the query will be put in modifiable mode + /// </returns> + public bool IsReadOnly(ISessionImplementor session) + { + return _isReadOnlyInitialized ? this.ReadOnly : session.PersistenceContext.DefaultReadOnly; + } } } \ No newline at end of file Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2011-02-11 14:44:33 UTC (rev 5379) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2011-02-11 16:07:38 UTC (rev 5380) @@ -17,10 +17,10 @@ namespace NHibernate.Engine { - /// <summary> + /// <summary> /// A <see cref="IPersistenceContext"/> represents the state of persistent "stuff" which /// NHibernate is tracking. This includes persistent entities, collections, - /// as well as proxies generated. + /// as well as proxies generated. /// </summary> /// <remarks> /// There is meant to be a one-to-one correspondence between a SessionImpl and @@ -97,6 +97,8 @@ [NonSerialized] private BatchFetchQueue batchFetchQueue; + private bool defaultReadOnly; + /// <summary> Constructs a PersistentContext, bound to the given session. </summary> /// <param name="session">The session "owning" this context. </param> public StatefulPersistenceContext(ISessionImplementor session) @@ -132,15 +134,15 @@ get { return false; } } - /// <summary> - /// Get the session to which this persistence context is bound. + /// <summary> + /// Get the session to which this persistence context is bound. /// </summary> public ISessionImplementor Session { get { return session; } } - /// <summary> + /// <summary> /// Retrieve this persistence context's managed load context. /// </summary> public LoadContexts LoadContexts @@ -154,7 +156,7 @@ } } - /// <summary> + /// <summary> /// Get the <tt>BatchFetchQueue</tt>, instantiating one if necessary. /// </summary> public BatchFetchQueue BatchFetchQueue @@ -221,7 +223,7 @@ unownedCollections[key] = collection; } - /// <summary> + /// <summary> /// Get and remove a collection whose owner is not yet loaded, /// when its owner is being loaded /// </summary> @@ -245,7 +247,8 @@ { foreach (INHibernateProxy proxy in proxiesByKey.Values) { - proxy.HibernateLazyInitializer.Session = null; + ILazyInitializer li = proxy.HibernateLazyInitializer; + li.UnsetSession(); } ICollection collectionEntryArray = IdentityMap.ConcurrentEntries(collectionEntries); @@ -283,6 +286,13 @@ { get { return hasNonReadOnlyEntities; } } + + /// <inheritdoc /> + public bool DefaultReadOnly + { + get { return defaultReadOnly; } + set { defaultReadOnly = value; } + } private void SetHasNonReadOnlyEnties(Status value) { @@ -307,9 +317,9 @@ entityEntry.LockMode = LockMode.None; } - /// <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> public object[] GetDatabaseSnapshot(object id, IEntityPersister persister) { @@ -327,7 +337,7 @@ } } - /// <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> @@ -352,9 +362,9 @@ return (object[])snapshot; } - /// <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> public object[] GetNaturalIdSnapshot(object id, IEntityPersister persister) @@ -408,7 +418,7 @@ BatchFetchQueue.RemoveBatchLoadableEntityKey(key); } - /// <summary> + /// <summary> /// Get the entity instance associated with the given <tt>EntityKey</tt> /// </summary> public object GetEntity(EntityKey key) @@ -424,7 +434,7 @@ return entitiesByKey.ContainsKey(key); } - /// <summary> + /// <summary> /// Remove an entity from the session cache, also clear /// up other state associated with the entity, all except /// for the <tt>EntityEntry</tt> @@ -465,8 +475,8 @@ entitiesByUniqueKey[euk] = entity; } - /// <summary> - /// Retrieve the EntityEntry representation of the given entity. + /// <summary> + /// Retrieve the EntityEntry representation of the given entity. /// </summary> /// <param name="entity">The entity for which to locate the EntityEntry. </param> /// <returns> The EntityEntry for the given entity. </returns> @@ -505,8 +515,8 @@ return AddEntry(entity, status, loadedState, null, entityKey.Identifier, version, lockMode, existsInDatabase, persister, disableVersionIncrement, lazyPropertiesAreUnfetched); } - /// <summary> - /// Generates an appropriate EntityEntry instance and adds it + /// <summary> + /// Generates an appropriate EntityEntry instance and adds it /// to the event source's internal caches. /// </summary> public EntityEntry AddEntry(object entity, Status status, object[] loadedState, object rowId, object id, @@ -534,8 +544,8 @@ return proxiesByKey.ContainsValue(proxy); } - /// <summary> - /// Takes the given object and, if it represents a proxy, reassociates it with this event source. + /// <summary> + /// Takes the given object and, if it represents a proxy, reassociates it with this event source. /// </summary> /// <param name="value">The possible proxy to be reassociated. </param> /// <returns> Whether the passed value represented an actual proxy which got initialized. </returns> @@ -560,9 +570,9 @@ } } - /// <summary> + /// <summary> /// If a deleted entity instance is re-saved, and it has a proxy, we need to - /// reset the identifier of the proxy + /// reset the identifier of the proxy /// </summary> public void ReassociateProxy(object value, object id) { @@ -585,7 +595,7 @@ } } - /// <summary> + /// <summary> /// Associate a proxy that was instantiated by another session with this session /// </summary> /// <param name="li">The proxy initializer. </param> @@ -605,7 +615,7 @@ } } - /// <summary> + /// <summary> /// Get the entity instance underlying the given proxy, throwing /// an exception if the proxy is uninitialized. If the given object /// is not a proxy, simply return the argument. @@ -626,7 +636,7 @@ if (li.IsUninitialized) throw new PersistentObjectException("object was an uninitialized proxy for " + li.PersistentClass.FullName); - return li.GetImplementation(); // unwrap the object + return li.GetImplementation(); // unwrap the object } else { @@ -634,8 +644,8 @@ } } - /// <summary> - /// Possibly unproxy the given reference and reassociate it with the current session. + /// <summary> + /// Possibly unproxy the given reference and reassociate it with the current session. /// </summary> /// <param name="maybeProxy">The reference to be unproxied if it currently represents a proxy. </param> /// <returns> The unproxied instance. </returns> @@ -652,12 +662,12 @@ { ILazyInitializer li = proxy.HibernateLazyInitializer; ReassociateProxy(li, proxy); - return li.GetImplementation(); //initialize + unwrap the object + return li.GetImplementation(); //initialize + unwrap the object } return maybeProxy; } - /// <summary> + /// <summary> /// Attempts to check whether the given key represents an entity already loaded within the /// current session. /// </summary> @@ -676,11 +686,11 @@ } } - /// <summary> + /// <summary> /// If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy /// and overwrite the registration of the old one. This breaks == and occurs only for /// "class" proxies rather than "interface" proxies. Also init the proxy to point to - /// the given target implementation if necessary. + /// the given target implementation if necessary. /// </summary> /// <param name="proxy">The proxy instance to be narrowed. </param> /// <param name="persister">The persister for the proxied entity. </param> @@ -706,7 +716,13 @@ else { proxy = (INHibernateProxy)persister.CreateProxy(key.Identifier, session); + INHibernateProxy proxyOrig = proxiesByKey[key]; proxiesByKey[key] = proxy; //overwrite old proxy + if (proxyOrig != null) + { + bool readOnlyOrig = proxyOrig.HibernateLazyInitializer.ReadOnly; + proxy.HibernateLazyInitializer.ReadOnly = readOnlyOrig; + } return proxy; } } @@ -720,7 +736,7 @@ } } - /// <summary> + /// <summary> /// Return the existing proxy associated with the given <tt>EntityKey</tt>, or the /// third argument (the entity associated with the key) if no proxy exists. Init /// the proxy to the target implementation, if necessary. @@ -741,7 +757,7 @@ } } - /// <summary> + /// <summary> /// Return the existing proxy associated with the given <tt>EntityKey</tt>, or the /// argument (the entity associated with the key) if no proxy exists. /// (slower than the form above) @@ -761,7 +777,7 @@ /// <summary> Get the entity that owned this persistent collection when it was loaded </summary> /// <param name="collection">The persistent collection </param> - /// <returns> + /// <returns> /// The owner, if its entity ID is available from the collection's loaded key /// and the owner entity is in the persistence context; otherwise, returns null /// </returns> @@ -819,7 +835,7 @@ AddCollection(collection, ce, collection.Key); } - /// <summary> + /// <summary> /// Add a new collection (ie. a newly created one, just instantiated by the /// application, with no database state or snapshot) /// </summary> @@ -865,7 +881,7 @@ collectionEntries[collection] = ce; } - /// <summary> + /// <summary> /// add an (initialized) collection that was created by another session and passed /// into update() (ie. one with a snapshot and existing state on the database) /// </summary> @@ -903,7 +919,7 @@ return null; } - /// <summary> + /// <summary> /// Register a collection for non-lazy loading at the end of the two-phase load /// </summary> public void AddNonLazyCollection(IPersistentCollection collection) @@ -911,7 +927,7 @@ nonlazyCollections.Add(collection); } - /// <summary> + /// <summary> /// Force initialization of all non-lazy collections encountered during /// the current two-phase load (actually, this is a no-op, unless this /// is the "outermost" load) @@ -953,7 +969,7 @@ } /// <summary> Register a <tt>PersistentCollection</tt> object for an array. - /// Associates a holder with an array - MUST be called after loading + /// Associates a holder with an array - MUST be called after loading /// array, since the array instance is not created until endLoad(). /// </summary> public void AddCollectionHolder(IPersistentCollection holder) @@ -962,7 +978,7 @@ arrayHolders[holder.GetValue()] = holder; } - /// <summary> + /// <summary> /// Remove the mapping of collection to holder during eviction of the owning entity /// </summary> public IPersistentCollection RemoveCollectionHolder(object array) @@ -978,7 +994,7 @@ return GetCollectionEntry(coll).Snapshot; } - /// <summary> + /// <summary> /// Get the collection entry for a collection passed to filter, /// which might be a collection wrapper, an array, or an unwrapped /// collection. Return null if there is no entry. @@ -1061,7 +1077,7 @@ loadCounter--; } - /// <summary> + /// <summary> /// Search the persistence context for an owner for the child object, /// given a collection role /// </summary> @@ -1071,7 +1087,7 @@ // TODO persistent context (BackrefPropertyAccessor) } - /// <summary> + /// <summary> /// Search the persistence context for an index of the child object, given a collection role /// </summary> public object GetIndexInOwner(string entity, string property, object childObject, IDictionary mergeMap) @@ -1080,7 +1096,7 @@ // TODO persistent context (IndexPropertyAccessor) } - /// <summary> + /// <summary> /// Record the fact that the association belonging to the keyed entity is null. /// </summary> public void AddNullProperty(EntityKey ownerKey, string propertyName) @@ -1094,18 +1110,80 @@ return nullAssociations.Contains(new AssociationKey(ownerKey, propertyName)); } - /// <summary> Set the object to read only and discard it's snapshot</summary> - public void SetReadOnly(object entity, bool readOnly) + public void SetReadOnly(object entityOrProxy, bool readOnly) { + if (entityOrProxy == null) + throw new ArgumentNullException("entityOrProxy"); + + if (IsReadOnly(entityOrProxy) == readOnly) + return; + + if (entityOrProxy is INHibernateProxy) + { + INHibernateProxy proxy = (INHibernateProxy)entityOrProxy; + SetProxyReadOnly(proxy, readOnly); + if (NHibernateUtil.IsInitialized(proxy)) + { + SetEntityReadOnly(proxy.HibernateLazyInitializer.GetImplementation(), readOnly); + } + } + else + { + SetEntityReadOnly(entityOrProxy, readOnly); + + // PersistenceContext.proxyFor( entity ) returns entity if there is no proxy for that entity + // so need to check the return value to be sure it is really a proxy + object maybeProxy = this.Session.PersistenceContext.ProxyFor(entityOrProxy); + if (maybeProxy is INHibernateProxy ) + { + SetProxyReadOnly((INHibernateProxy)maybeProxy, readOnly); + } + } + } + + private void SetProxyReadOnly(INHibernateProxy proxy, bool readOnly) + { + if (proxy.HibernateLazyInitializer.Session != this.Session) + { + throw new AssertionFailure("Attempt to set a proxy to read-only that is associated with a different session"); + } + proxy.HibernateLazyInitializer.ReadOnly = readOnly; + } + + private void SetEntityReadOnly(object entity, bool readOnly) + { EntityEntry entry = GetEntry(entity); if (entry == null) { - throw new TransientObjectException("Instance of" + entity.GetType() + " was not associated with the session"); + throw new TransientObjectException("Instance was not associated with this persistence context"); } entry.SetReadOnly(readOnly, entity); hasNonReadOnlyEntities |= !readOnly; } - + + public bool IsReadOnly(object entityOrProxy) + { + if (entityOrProxy == null) + { + throw new AssertionFailure("object must be non-null."); + } + bool isReadOnly; + if (entityOrProxy is INHibernateProxy) + { + isReadOnly = ((INHibernateProxy)entityOrProxy).HibernateLazyInitia... [truncated message content] |
From: <jul...@us...> - 2011-02-24 14:37:51
|
Revision: 5396 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5396&view=rev Author: julian-maughan Date: 2011-02-24 14:37:45 +0000 (Thu, 24 Feb 2011) Log Message: ----------- XML documentation refinements for read-only entity APIs. Modified Paths: -------------- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/ICriteria.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/IQuery.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/ISession.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/CriteriaImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/SessionImpl.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/AbstractLazyInitializer.cs branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/ILazyInitializer.cs Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -55,38 +55,21 @@ bool Flushing { get; set;} /// <summary> - /// Change the default for entities and proxies loaded into this persistence - /// context from modifiable to read-only mode, or from modifiable to read-only - /// mode. + /// The read-only status for entities (and proxies) loaded into this persistence context. /// </summary> /// <remarks> /// <para> - /// Read-only entities are not dirty-checked and snapshots of persistent - /// state are not maintained. Read-only entities can be modified, but - /// changes are not persisted. + /// 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> - /// When a proxy is initialized, the loaded entity will have the same - /// read-only/modifiable setting as the uninitialized - /// proxy has, regardless of the persistence context's current setting. + /// 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> - /// <para> - /// To change the read-only/modifiable setting for a particular entity - /// or proxy that is already in this session: - /// <see cref="SetReadOnly(object, bool)" /> - /// <see cref="ISession.SetReadOnly(object, bool)" /> - /// </para> - /// <para> - /// To determine the read-only/modifiable setting for a particular entity or proxy: - /// <see cref="IsReadOnly(object)" /> - /// <see cref="ISession.IsReadOnly(object)" /> - /// </para> - /// <para> - /// To override this session's read-only/modifiable setting for entities - /// and proxies loaded by an IQuery: - /// <see cref="IQuery.SetReadOnly(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> @@ -377,53 +360,36 @@ bool IsPropertyNull(EntityKey ownerKey, string propertyName); /// <summary> - /// Set the entity or proxy to read only and discard it's snapshot. - /// Set an unmodified persistent object to read-only mode, or a read-only - /// object to modifiable mode. + /// Change the read-only status of an entity (or proxy). /// </summary> /// <remarks> /// <para> - /// Read-only entities are not dirty-checked and snapshots of persistent - /// state are not maintained. Read-only entities can be modified, but - /// changes are not persisted. + /// Read-only entities can be modified, but changes are not persisted. They are not dirty-checked + /// and snapshots of persistent state are not maintained. /// </para> /// <para> - /// When a proxy is initialized, the loaded entity will have the same - /// read-only/modifiable setting as the uninitialized - /// proxy has, regardless of the session's current setting. + /// Immutable entities cannot be made read-only. /// </para> /// <para> - /// If the entity or proxy already has the specified read-only/modifiable - /// setting, then this method does nothing. + /// To set the <em>default</em> read-only setting for entities and proxies that are loaded + /// into the persistence context, see <see cref="IPersistenceContext.DefaultReadOnly" />. /// </para> - /// <para> - /// To set the default read-only/modifiable setting used for - /// entities and proxies that are loaded into this persistence context: - /// <see cref="IPersistenceContext.DefaultReadOnly" /> - /// <see cref="ISession.DefaultReadOnly" /> - /// </para> - /// <para> - /// To override this persistence context's read-only/modifiable setting - /// for entities and proxies loaded by a Query: - /// <see cref="IQuery.SetReadOnly(bool)" /> - /// </para> /// </remarks> - /// <param name="entity">An entity or INHibernateProxy</param> - /// <param name="readOnly">if <c>true</c>, the entity or proxy is made read-only; if <c>false</c>, the entity or proxy is made modifiable.</param> - /// <seealso cref="ISession.SetReadOnly(object, bool)" /> - void SetReadOnly(object entity, bool readOnly); + /// <param name="entityOrProxy">An entity (or <see cref="NHibernate.Proxy.INHibernateProxy" />).</param> + /// <param name="readOnly">If <c>true</c>, the entity or proxy is made read-only; if <c>false</c>, it is made modifiable.</param> + /// <seealso cref="IPersistenceContext.DefaultReadOnly" /> + /// <seealso cref="IPersistenceContext.IsReadOnly(object)" /> + void SetReadOnly(object entityOrProxy, bool readOnly); /// <summary> - /// Is the entity or proxy read-only? + /// Is the specified entity (or proxy) read-only? /// </summary> - /// <remarks> - /// To get the default read-only/modifiable setting used for - /// entities and proxies that are loaded into the session: - /// <see cref="ISession.DefaultReadOnly" /> - /// </remarks> + /// <param name="entityOrProxy">An entity (or <see cref="NHibernate.Proxy.INHibernateProxy" />)</param> /// <returns> - /// <c>true</c>, the object is read-only; <c>false</c>, the object is modifiable. + /// <c>true</c> if the entity or proxy is read-only, otherwise <c>false</c>. /// </returns> + /// <seealso cref="IPersistenceContext.DefaultReadOnly" /> + /// <seealso cref="IPersistenceContext.SetReadOnly(object, bool)" /> bool IsReadOnly(object entityOrProxy); void ReplaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, object generatedId); Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -16,7 +16,7 @@ namespace NHibernate.Engine { /// <summary> - /// Defines the internal contract between the <c>Session</c> and other parts of Hibernate + /// Defines the internal contract between the <c>Session</c> and other parts of NHibernate /// such as implementors of <c>Type</c> or <c>ClassPersister</c> /// </summary> public interface ISessionImplementor Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -168,14 +168,6 @@ set { _lockModes = value; } } - /// <summary> - /// Has the read-only/modifiable mode been explicitly set? - /// </summary> - /// <value> - /// <c>true</c>, the read-only/modifiable mode was explicitly set; <c>false</c>, the read-only/modifiable mode was not explicitly set - /// </value> - /// <seealso cref="ReadOnly" /> - /// <seealso cref="IsReadOnly(ISessionImplementor)" /> public bool IsReadOnlyInitialized { get { return _isReadOnlyInitialized; } @@ -281,15 +273,6 @@ public bool Callable { get; set; } - /// <summary> - /// Should entities and proxies loaded by the query be put in read-only mode? - /// </summary> - /// <remarks> - /// The read-only/modifiable setting has no impact on entities/proxies returned by the - /// query that existed in the session before the query was executed. - /// </remarks> - /// <seealso cref="IsReadOnlyInitialized" /> - /// <seealso cref="IsReadOnly(ISessionImplementor)" /> public bool ReadOnly { get @@ -693,23 +676,6 @@ return copy; } - /// <summary> - /// Should entities and proxies loaded by the query be put in read-only mode? If the - /// read-only/modifiable setting was not initialized - /// (i.e. <see cref="IsReadOnlyInitialized" /> == false), then the default - /// read-only/modifiable setting for the persistence context is returned instead. - /// </summary> - /// <remarks> - /// The read-only/modifiable setting has no impact on entities/proxies returned by the - /// query that existed in the session before the query was executed. - /// </remarks> - /// <seealso cref="IsReadOnlyInitialized" /> - /// <seealso cref="ReadOnly" /> - /// <seealso cref="IPersistenceContext.DefaultReadOnly" /> - /// <param name="session"></param> - /// <returns> - /// <c>true</c>, entities and proxies loaded by the query will be put in read-only mode; <c>false</c>, entities and proxies loaded by the query will be put in modifiable mode - /// </returns> public bool IsReadOnly(ISessionImplementor session) { return _isReadOnlyInitialized ? this.ReadOnly : session.PersistenceContext.DefaultReadOnly; Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -1113,6 +1113,7 @@ return nullAssociations.Contains(new AssociationKey(ownerKey, propertyName)); } + /// <inheritdoc /> public void SetReadOnly(object entityOrProxy, bool readOnly) { if (entityOrProxy == null) @@ -1164,6 +1165,7 @@ hasNonReadOnlyEntities |= !readOnly; } + /// <inheritdoc /> public bool IsReadOnly(object entityOrProxy) { if (entityOrProxy == null) Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/ICriteria.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/ICriteria.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/ICriteria.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -61,26 +61,32 @@ string Alias { get; } /// <summary> - /// Was the read-only/modifiable mode explicitly initialized? + /// Was the read-only mode explicitly initialized? /// </summary> - /// <seealso cref="SetReadOnly(bool)" /> - /// <returns><c>true</c>, the read-only/modifiable mode was explicitly initialized; <c>false</c>, otherwise.</returns> + /// <returns><c>true</c> if the read-only mode was explicitly initialized, otherwise <c>false</c>.</returns> + /// <seealso cref="ICriteria.SetReadOnly(bool)" /> + /// <seealso cref="ICriteria.IsReadOnly" />/// bool IsReadOnlyInitialized { get; } /// <summary> - /// Should entities and proxies loaded by this Criteria be put in read-only mode? If the - /// read-only/modifiable setting was not initialized, then the default - /// read-only/modifiable setting for the persistence context is returned instead. + /// Will entities (and proxies) loaded by this Criteria be put in read-only mode? /// </summary> /// <remarks> - /// The read-only/modifiable setting has no impact on entities/proxies returned by the + /// <para> + /// If the read-only setting was not initialized, then the value of the session's + /// <see cref="ISession.DefaultReadOnly" /> property is returned instead. + /// </para> + /// <para> + /// The read-only setting has no impact on entities or proxies returned by the /// Criteria that existed in the session before the Criteria was executed. + /// </para> /// </remarks> - /// <seealso cref="SetReadOnly(bool)" /> - /// <seealso cref="NHibernate.Engine.IPersistenceContext.DefaultReadOnly" /> /// <returns> - /// <c>true</c>, entities and proxies loaded by the criteria will be put in read-only mode; <c>false</c>, entities and proxies loaded by the criteria will be put in modifiable mode + /// <c>true</c> if entities and proxies loaded by the criteria will be put in read-only mode, + /// otherwise <c>false</c>. /// </returns> + /// <seealso cref="ICriteria.SetReadOnly(bool)" /> + /// <seealso cref="ICriteria.IsReadOnlyInitialized" /> bool IsReadOnly { get; } /// <summary> @@ -310,28 +316,33 @@ IFutureValue<T> FutureValue<T>(); /// <summary> - /// Set the read-only/modifiable mode for entities and proxies - /// loaded by this Criteria. This setting overrides the default setting - /// for the persistence context. + /// Set the read-only mode for entities (and proxies) loaded by this Criteria. This + /// setting overrides the default for the session (see <see cref="ISession.DefaultReadOnly" />). /// </summary> /// <remarks> - /// <para>Use <see cref="NHibernate.Engine.IPersistenceContext.DefaultReadOnly" /> or - /// <see cref="NHibernate.ISession.DefaultReadOnly" /> to set the default read-only/modifiable - /// setting used for entities and proxies that are loaded into the session.</para> - /// <para>Read-only entities are not dirty-checked and snapshots of persistent - /// state are not maintained. Read-only entities can be modified, but - /// changes are not persisted.</para> - /// <para>When a proxy is initialized, the loaded entity will have the same - /// read-only/modifiable setting as the uninitialized proxy has, regardless - /// of the session's current setting.</para> - /// <para>The read-only/modifiable setting has no impact on entities/proxies - /// returned by the criteria that existed in the session before the criteria was - /// executed.</para> + /// <para> + /// To set the <em>default</em> read-only setting for entities and proxies that are loaded + /// into the session, see <see cref="ISession.DefaultReadOnly" />. + /// </para> + /// <para> + /// Read-only entities can be modified, but changes are not persisted. They are not + /// dirty-checked and snapshots of persistent state are not maintained. + /// </para> + /// <para> + /// When a proxy is initialized, the loaded entity will have the same read-only setting + /// as the uninitialized proxy has, regardless of the session's current setting. + /// </para> + /// <para> + /// The read-only setting has no impact on entities or proxies returned by the criteria + /// that existed in the session before the criteria was executed. + /// </para> /// </remarks> /// <param name="readOnly"> - /// <c>true</c>, entities and proxies loaded by the criteria will be put in read-only mode; <c>false</c>, entities and proxies loaded by the criteria will be put in modifiable mode + /// If <c>true</c>, entities (and proxies) loaded by the criteria will be read-only. /// </param> /// <returns><c>this</c> (for method chaining)</returns> + /// <seealso cref="ICriteria.IsReadOnly" /> + /// <seealso cref="ICriteria.IsReadOnlyInitialized" /> ICriteria SetReadOnly(bool readOnly); #region NHibernate specific Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/IQuery.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/IQuery.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/IQuery.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -67,7 +67,7 @@ IType[] ReturnTypes { get; } /// <summary> Return the HQL select clause aliases (if any)</summary> - /// <returns> an array of aliases as strings </returns> + /// <returns> An array of aliases as strings </returns> string[] ReturnAliases { get; } /// <summary> @@ -77,19 +77,23 @@ string[] NamedParameters { get; } /// <summary> - /// Should entities and proxies loaded by this query be put in read-only mode? If the - /// read-only/modifiable setting was not initialized, then the default - /// read-only/modifiable setting for the persistence context is returned instead. + /// Will entities (and proxies) returned by the query be loaded in read-only mode? /// </summary> /// <remarks> - /// The read-only/modifiable setting has no impact on entities/proxies returned by the + /// <para> + /// If the query's read-only setting is not initialized (with <see cref="SetReadOnly(bool)" />), + /// the value of the session's <see cref="ISession.DefaultReadOnly" /> property is + /// returned instead. + /// </para> + /// <para> + /// The value of this property has no effect on entities or proxies returned by the /// query that existed in the session before the query was executed. + /// </para> /// </remarks> /// <returns> - /// <c>true</c>, entities and proxies loaded by the query will be put in read-only mode; <c>false</c>, entities and proxies loaded by the query will be put in modifiable mode + /// <c>true</c> if entities and proxies loaded by the query will be put in read-only mode, otherwise <c>false</c>. /// </returns> - /// <seealso cref="SetReadOnly(bool)" /> - /// <seealso cref="NHibernate.Engine.IPersistenceContext.DefaultReadOnly()" /> + /// <seealso cref="IQuery.SetReadOnly(bool)" /> bool IsReadOnly { get; } /// <summary> @@ -171,13 +175,28 @@ IQuery SetFirstResult(int firstResult); /// <summary> - /// Entities retrieved by this query will be loaded in - /// a read-only mode where NHibernate will never dirty-check - /// them or make changes persistent. + /// Set the read-only mode for entities (and proxies) loaded by this query. This setting + /// overrides the default setting for the session (see <see cref="ISession.DefaultReadOnly" />). /// </summary> + /// <remarks> + /// <para> + /// Read-only entities can be modified, but changes are not persisted. They are not + /// dirty-checked and snapshots of persistent state are not maintained. + /// </para> + /// <para> + /// When a proxy is initialized, the loaded entity will have the same read-only setting + /// as the uninitialized proxy, regardless of the session's current setting. + /// </para> + /// <para> + /// The read-only setting has no impact on entities or proxies returned by the criteria + /// that existed in the session before the criteria was executed. + /// </para> + /// </remarks> /// <param name="readOnly"> - /// <c>true</c>, entities and proxies loaded by the query will be put in read-only mode; <c>false</c>, entities and proxies loaded by the query will be put in modifiable mode + /// If <c>true</c>, entities (and proxies) loaded by the query will be read-only. /// </param> + /// <returns><c>this</c> (for method chaining)</returns> + /// <seealso cref="IsReadOnly" /> IQuery SetReadOnly(bool readOnly); /// <summary> Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/ISession.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/ISession.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/ISession.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -179,71 +179,66 @@ bool IsDirty(); /// <summary> - /// Is the specified entity or proxy read-only? + /// Is the specified entity (or proxy) read-only? /// </summary> /// <remarks> - /// To get the default read-only/modifiable setting used for - /// entities and proxies that are loaded into the session: - /// <see cref="DefaultReadOnly" /> + /// Facade for <see cref="IPersistenceContext.IsReadOnly(object)" />. /// </remarks> - /// <param name="entityOrProxy">An entity or INHibernateProxy</param> + /// <param name="entityOrProxy">An entity (or <see cref="NHibernate.Proxy.INHibernateProxy" />)</param> /// <returns> - /// <c>true</c>, the entity or proxy is read-only; <c>false</c>, the entity or proxy is modifiable. + /// <c>true</c> if the entity (or proxy) is read-only, otherwise <c>false</c>. /// </returns> + /// <seealso cref="ISession.DefaultReadOnly" /> + /// <seealso cref="ISession.SetReadOnly(object, bool)" /> bool IsReadOnly(object entityOrProxy); /// <summary> - /// Set an unmodified persistent object to read-only mode, or a read-only - /// object to modifiable mode. In read-only mode, no snapshot is maintained, - /// the instance is never dirty checked, and changes are not persisted. + /// Change the read-only status of an entity (or proxy). /// </summary> /// <remarks> /// <para> - /// If the entity or proxy already has the specified read-only/modifiable - /// setting, then this method does nothing. + /// Read-only entities can be modified, but changes are not persisted. They are not dirty-checked + /// and snapshots of persistent state are not maintained. /// </para> /// <para> - /// To set the default read-only/modifiable setting used for - /// entities and proxies that are loaded into the session: - /// <see cref="ISession.DefaultReadOnly" /> + /// Immutable entities cannot be made read-only. /// </para> /// <para> - /// To override this session's read-only/modifiable setting for entities - /// and proxies loaded by a query: - /// <see cref="IQuery.SetReadOnly(bool)" /> + /// To set the <em>default</em> read-only setting for entities and proxies that are loaded + /// into the session, see <see cref="ISession.DefaultReadOnly" />. /// </para> + /// <para> + /// This method a facade for <see cref="IPersistenceContext.SetReadOnly(object, bool)" />. + /// </para> /// </remarks> - /// <param name="entityOrProxy">An entity or INHibernateProxy</param> - /// <param name="readOnly">if <c>true</c>, the entity or proxy is made read-only; if <c>false</c>, the entity or proxy is made modifiable.</param> + /// <param name="entityOrProxy">An entity (or <see cref="NHibernate.Proxy.INHibernateProxy" />).</param> + /// <param name="readOnly">If <c>true</c>, the entity or proxy is made read-only; if <c>false</c>, it is made modifiable.</param> + /// <seealso cref="ISession.DefaultReadOnly" /> + /// <seealso cref="ISession.IsReadOnly(object)" /> void SetReadOnly(object entityOrProxy, bool readOnly); /// <summary> - /// The default read-only status of the Session - /// Will entities and proxies that are loaded into this session be made - /// read-only by default? + /// The read-only status for entities (and proxies) loaded into this Session. /// </summary> /// <remarks> /// <para> - /// Read-only entities are not dirty-checked and snapshots of persistent - /// state are not maintained. Read-only entities can be modified, but - /// changes are not persisted. + /// When a proxy is initialized, the loaded entity will have the same read-only setting + /// as the uninitialized proxy, regardless of the session's current setting. /// </para> /// <para> - /// When a proxy is initialized, the loaded entity will have the same - /// read-only/modifiable setting as the uninitialized - /// proxy has, regardless of the session's current setting. + /// To change the read-only setting for a particular entity or proxy that is already in + /// this session, see <see cref="ISession.SetReadOnly(object, bool)" />. /// </para> /// <para> - /// To change the read-only/modifiable setting for a particular entity - /// or proxy that is already in this session: - /// <see cref="ISession.SetReadOnly(object, bool)" /> + /// To override this session's read-only setting for entities and proxies loaded by a query, + /// see <see cref="IQuery.SetReadOnly(bool)" />. /// </para> /// <para> - /// To override this session's read-only/modifiable setting for entities - /// and proxies loaded by a query: - /// <see cref="IQuery.SetReadOnly(bool)" /> + /// This method is a facade for <see cref="IPersistenceContext.DefaultReadOnly" />. /// </para> /// </remarks> + /// <seealso cref="ISession.IsReadOnly(object)" /> + /// <seealso cref="ISession.SetReadOnly(object, bool)" /> bool DefaultReadOnly { get; set; } /// <summary> Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/CriteriaImpl.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/CriteriaImpl.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/CriteriaImpl.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -124,11 +124,13 @@ get { return projection; } } + /// <inheritdoc /> public bool IsReadOnlyInitialized { get { return (readOnly != null); } } + /// <inheritdoc /> public bool IsReadOnly { get @@ -496,7 +498,8 @@ return this; } - + + /// <inheritdoc /> public ICriteria SetReadOnly(bool readOnly) { this.readOnly = readOnly; @@ -795,12 +798,12 @@ return root.FutureValue<T>(); } - public IEnumerable<T> Future<T>() - { - return root.Future<T>(); - } + public IEnumerable<T> Future<T>() + { + return root.Future<T>(); + } - public void List(IList results) + public void List(IList results) { root.List(results); } Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -2394,12 +2394,12 @@ } /// <inheritdoc /> - public void SetReadOnly(object entity, bool readOnly) + public void SetReadOnly(object entityOrProxy, bool readOnly) { using (new SessionIdLoggingContext(SessionId)) { CheckAndUpdateSessionStatus(); - persistenceContext.SetReadOnly(entity, readOnly); + persistenceContext.SetReadOnly(entityOrProxy, readOnly); } } Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/AbstractLazyInitializer.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/AbstractLazyInitializer.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/AbstractLazyInitializer.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -50,6 +50,7 @@ SetSession(session); } + /// <inheritdoc /> public void SetSession(ISessionImplementor s) { if (s != _session) @@ -84,6 +85,7 @@ } } + /// <inheritdoc /> public void UnsetSession() { _session = null; @@ -207,6 +209,7 @@ initialized = true; } + /// <inheritdoc /> public bool IsReadOnlySettingAvailable { get { return (_session != null && !_session.IsClosed); } Modified: branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/ILazyInitializer.cs =================================================================== --- branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/ILazyInitializer.cs 2011-02-24 13:58:45 UTC (rev 5395) +++ branches/ReadOnlyEntities/nhibernate/src/NHibernate/Proxy/ILazyInitializer.cs 2011-02-24 14:37:45 UTC (rev 5396) @@ -40,7 +40,7 @@ ISessionImplementor Session { get; set; } /// <summary> - /// Is the proxy's read-only/modifiable setting available? + /// Is the read-only setting available? /// </summary> bool IsReadOnlySettingAvailable { get; } @@ -49,22 +49,15 @@ /// </summary> /// <remarks> /// <para> - /// The read-only/modifiable setting is not available when the proxy is - /// detached or its associated session is closed. + /// Not available when the proxy is detached or its associated session is closed. /// </para> /// <para> - /// If the proxy is currently initialized, its implementation will be set to - /// the same mode; otherwise, when the proxy is initialized, its implementation - /// will have the same read-only/modifiable setting as the proxy. In read-only - /// mode, no snapshot is maintained and the instance is never dirty checked. - /// </para> + /// To check if the read-only setting is available, use <see cref="IsReadOnlySettingAvailable" /> + /// </para> /// <para> - /// If the associated proxy already has the specified read-only/modifiable - /// setting, then this method does nothing. + /// The read-only status of the entity will be made to match the read-only status of the proxy + /// upon initialization. /// </para> - /// <para> - /// To check if the read-only/modifiable setting is available: <see cref="IsReadOnlySettingAvailable" /> - /// </para> /// </remarks> bool ReadOnly { get; set; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |