예제 #1
0
        public void TestCachingReadOnlyEntity( )
        {
            using (new EntitySnapshotContext( ))
            {
                var nameField = Entity.Get <Field>(new EntityRef("core", "name"));

                EntitySnapshotContextData snaphotData = EntitySnapshotContext.GetContextData( );

                IEntity cachedEntity;
                Assert.IsTrue(snaphotData.TryGetEntity(nameField.Id, out cachedEntity), "The entity should be cached");
            }
        }
        /// <summary>
        ///     Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="disposing">
        ///     <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (_isOwnerContext)
                {
                    // This class is the owner so free the context data
                    _snapshotData = null;
                }

                _disposed = true;
            }
        }
 /// <summary>
 ///     Initializes a new instance of the <see cref="EntitySnapshotContext" /> class.
 /// </summary>
 public EntitySnapshotContext( )
 {
     // Check the context for a current entity snapshot data
     if (_snapshotData == null)
     {
         // Did not find one, so create one and mark the current class as the owner.
         _isOwnerContext = true;
         _snapshotData   = new EntitySnapshotContextData( );
     }
     else
     {
         // Otherwise just borrow the current snapshot data.
         _isOwnerContext = false;
     }
 }
예제 #4
0
        public void TestNestedSnapshotCachingReadonlyEntity( )
        {
            using (new EntitySnapshotContext( ))
            {
                long nameFieldId;
                using (new EntitySnapshotContext( ))
                {
                    var nameField = Entity.Get <Field>(new EntityRef("core", "name"));
                    nameFieldId = nameField.Id;

                    EntitySnapshotContextData snaphotData2 = EntitySnapshotContext.GetContextData( );

                    IEntity cachedEntity2;
                    Assert.IsTrue(snaphotData2.TryGetEntity(nameFieldId, out cachedEntity2), "The entity should be cached");
                }

                EntitySnapshotContextData snaphotData1 = EntitySnapshotContext.GetContextData( );

                IEntity cachedEntity1;
                Assert.IsTrue(snaphotData1.TryGetEntity(nameFieldId, out cachedEntity1), "The entity should be cached");
            }
        }
예제 #5
0
        public void TestCachingReadOnlyEntityIgnoreWrites( )
        {
            // Note: in order to remove dependencies on 'Shared' objects, the following changes were made in this test:
            // 'Organisation' got changed to 'Report'
            // 'Employee' got changed to 'ReportColumn'
            // 'WorksFor' got changed to 'ColumnForReport'

            var organisationA = new Report( );

            organisationA.Save( );

            var organisationB = new Report();

            organisationB.Save( );

            var organisationC = new Report();

            organisationC.Save( );

            var employee = new ReportColumn
            {
                Name            = "Initial Name",
                ColumnForReport = organisationA
            };

            employee.Save( );

            using (new EntitySnapshotContext( ))
            {
                // This will cache the employee
                var readOnlyEmployee = Entity.Get <ReportColumn>(employee.Id);

                EntitySnapshotContextData snaphotData = EntitySnapshotContext.GetContextData( );

                IEntity cachedEntity;
                Assert.IsTrue(snaphotData.TryGetEntity(readOnlyEmployee.Id, out cachedEntity), "The entity should be cached");
                Assert.AreEqual("Initial Name", readOnlyEmployee.Name, "The name of the read only employee is invalid");
                Assert.AreEqual(organisationA.Id, readOnlyEmployee.ColumnForReport.Id, "The organisation of the read only employee is invalid");

                // Get a writable copy and change the name & organisation
                var writeableEmployee = readOnlyEmployee.AsWritable <ReportColumn>();
                writeableEmployee.Name            = "New Name";
                writeableEmployee.ColumnForReport = organisationB;
                writeableEmployee.Save( );

                // Ensure that requesting a read only employee returns the cached one
                readOnlyEmployee = Entity.Get <ReportColumn>(employee.Id);
                Assert.AreEqual("Initial Name", readOnlyEmployee.Name);
                Assert.AreEqual(organisationA.Id, readOnlyEmployee.ColumnForReport.Id, "The organisation of the read only employee is invalid");

                // Ensure that requesting a writeable employee returns the new one
                writeableEmployee = Entity.Get <ReportColumn>(employee.Id, true);
                Assert.AreEqual("New Name", writeableEmployee.Name);
                Assert.AreEqual(organisationB.Id, writeableEmployee.ColumnForReport.Id, "The organisation of the writeable employee is invalid");
            }

            // This will cache the employee
            var readOnlyEmployee2 = Entity.Get <ReportColumn>(employee.Id);

            Assert.AreEqual("New Name", readOnlyEmployee2.Name);
            Assert.AreEqual(organisationB.Id, readOnlyEmployee2.ColumnForReport.Id, "The organisation of the read only employee is invalid");

            // Get a writable copy and change the name
            var writeableEmployee2 = readOnlyEmployee2.AsWritable <ReportColumn>();

            writeableEmployee2.Name            = "New Name2";
            writeableEmployee2.ColumnForReport = organisationC;
            writeableEmployee2.Save( );

            // Ensure that requesting a read only employee returns the new one
            readOnlyEmployee2 = Entity.Get <ReportColumn>(employee.Id);
            Assert.AreEqual("New Name2", readOnlyEmployee2.Name);
            Assert.AreEqual(organisationC.Id, readOnlyEmployee2.ColumnForReport.Id, "The organisation of the read only employee is invalid");

            // Ensure that requesting a writeable employee returns the new one
            writeableEmployee2 = Entity.Get <ReportColumn>(employee.Id, true);
            Assert.AreEqual("New Name2", writeableEmployee2.Name);
            Assert.AreEqual(organisationC.Id, writeableEmployee2.ColumnForReport.Id, "The organisation of the writeable employee is invalid");
        }
예제 #6
0
        public void TestMultipleThreads( )
        {
            bool thread1Failed = true;
            bool thread2Failed = true;

            var startEvent = new ManualResetEvent(false);
            var thread1GotNameFieldEvent        = new ManualResetEvent(false);
            var thread2GotDescriptionFieldEvent = new ManualResetEvent(false);

            string thread1Result = string.Empty;
            string thread2Result = string.Empty;

            var thread1 = new Thread(() =>
            {
                startEvent.WaitOne( );

                var descriptionField = Entity.Get <Field>(new EntityRef("core", "description"));

                using (new EntitySnapshotContext( ))
                {
                    // The name field should be cached for this thread
                    var nameField = Entity.Get <Field>(new EntityRef("core", "name"));

                    EntitySnapshotContextData snaphotData = EntitySnapshotContext.GetContextData( );

                    // Wait for thread2 to have the description field cached
                    thread1GotNameFieldEvent.Set( );
                    thread2GotDescriptionFieldEvent.WaitOne( );

                    IEntity cachedEntity;
                    if (!snaphotData.TryGetEntity(nameField.Id, out cachedEntity))
                    {
                        thread1Result = "The name entity should be cached";
                    }
                    else if (snaphotData.TryGetEntity(descriptionField.Id, out cachedEntity))
                    {
                        thread1Result = "The description entity should not be cached";
                    }
                    else
                    {
                        thread1Failed = false;
                    }
                }
            });

            var thread2 = new Thread(() =>
            {
                startEvent.WaitOne( );

                var nameField = Entity.Get <Field>(new EntityRef("core", "name"));

                using (new EntitySnapshotContext( ))
                {
                    // The description field should be cached for this thread
                    var descriptionField = Entity.Get <Field>(new EntityRef("core", "description"));

                    EntitySnapshotContextData snaphotData = EntitySnapshotContext.GetContextData( );

                    // Wait for thread1 to have the name field cached
                    thread2GotDescriptionFieldEvent.Set( );
                    thread1GotNameFieldEvent.WaitOne( );

                    IEntity cachedEntity;
                    if (!snaphotData.TryGetEntity(descriptionField.Id, out cachedEntity))
                    {
                        thread2Result = "The description entity should be cached";
                    }
                    else if (snaphotData.TryGetEntity(nameField.Id, out cachedEntity))
                    {
                        thread2Result = "The name entity should not be cached";
                    }
                    else
                    {
                        thread2Failed = false;
                    }
                }
            });

            thread1.Start( );
            thread2.Start( );

            startEvent.Set( );

            thread1.Join( );
            thread2.Join( );

            Assert.IsFalse(thread1Failed, "Thread 1 failed: " + thread1Result);
            Assert.IsFalse(thread2Failed, "Thread 2 failed: " + thread2Result);
        }
예제 #7
0
            /// <summary>
            ///     Retrieves the entity.
            /// </summary>
            /// <param name="entityRef">The entity ref.</param>
            /// <returns>
            ///     The current entity if found; null otherwise.
            /// </returns>
            private IEntity RetrieveEntity(EntityRef entityRef)
            {
                if (entityRef.HasId)
                {
                    Trace.TraceEntityGetById(entityRef.Id);
                }
                else if (entityRef.HasEntity)
                {
                    Trace.TraceEntityGetById(entityRef.Entity.Id);
                }
                else
                {
                    Trace.TraceEntityGetByAlias(string.IsNullOrEmpty(entityRef.Namespace) ? entityRef.Alias : string.Format("{0}:{1}", entityRef.Namespace, entityRef.Alias));
                }

                EntitySnapshotContextData snapshotContext = null;

                if (!_writable)
                {
                    snapshotContext = EntitySnapshotContext.GetContextData( );

                    if (snapshotContext != null)
                    {
                        IEntity cachedEntity;
                        if (snapshotContext.TryGetEntity(entityRef.Id, out cachedEntity))
                        {
                            return(cachedEntity);
                        }
                    }
                }

                IEntity entity;

                var localEntityCache = GetLocalCache( );

                if (entityRef.HasEntity)
                {
                    /////
                    // Use the stored entity.
                    /////
                    entity = entityRef.Entity;
                }
                else if (IsWriteable && localEntityCache.TryGetValue(entityRef.Id, out entity))
                {
                    /////
                    // Local Call Context contains the entity.
                    /////
                }
                else if (!EntityCache.Instance.TryGetValue(entityRef.Id, out entity))
                {
                    /////
                    // Cache hit failed, retrieve from database.
                    /////
                    if (_retrievalResults == null)
                    {
                        _retrievalResults = _retrievalFunction( ).ToDictionary(activationDataInstance => activationDataInstance.Id);
                    }

                    ActivationData activationData;

                    if (!_retrievalResults.TryGetValue(entityRef.Id, out activationData))
                    {
                        if (!localEntityCache.TryGetValue(entityRef.Id, out entity))
                        {
                            EntityCache.Instance.TryGetValue(entityRef.Id, out entity);
                        }
                        /////
                        // Try the cache one last time
                        /////
                        if (entity == null)
                        {
                            /////
                            // Entity not found in the database, skipping.
                            /////

                            if (snapshotContext != null)
                            {
                                snapshotContext.SetEntity(entityRef.Id, null);
                            }

                            return(null);
                        }
                    }
                    else
                    {
                        entity = _activationFunction(activationData);
                    }
                }

                if (snapshotContext != null)
                {
                    snapshotContext.SetEntity(entity.Id, entity);
                }

                return(entity);
            }