Пример #1
0
        /// <summary>Finds all the entities that match the expression.</summary>
        /// <param name="expression">The search-specification.</param>
        /// <param name="sortRules">The specification of the sort rules that must be applied. Use <see langword="null"/> to ignore the ordering.</param>
        /// <param name="maximumResults">The maximum number of results that must be retrieved. Use '-1' to retrieve all results.</param>
        /// <param name="includePaths">The dot-separated lists of related objects to return in the query results.</param>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        /// <returns>The items that match the expression.</returns>
        protected override IEnumerable <TEntity> FindAllCore(Func <TEntity, bool> expression,
                                                             SortSpecifications <TEntity> sortRules, int maximumResults, string[] includePaths, DataSourceInfo dataSourceInfo)
        {
            MemoryStore <TEntity> memoryStore = this.SelectMemoryStore(dataSourceInfo);

            try {
                this.temporaryStorageLock.EnterReadLock();
                memoryStore.EnterReadLock();

                IEnumerable <TEntity> results = this.ConcatStorage(dataSourceInfo);
                results = results.Where(item => expression(item)).OrderBy(sortRules);

                if (maximumResults == -1)
                {
                    return(results.ToList());
                }
                else
                {
                    return(results.Take(maximumResults).ToList());
                }
            }
            finally {
                memoryStore.ExitReadLock();
                this.temporaryStorageLock.ExitReadLock();
            }
        }
Пример #2
0
        /// <summary>Finds the single entity that matches the expression or returns the default value if there were no matches.</summary>
        /// <param name="expression">The search-specification.</param>
        /// <param name="includePaths">The dot-separated lists of related objects to return in the query results.</param>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        /// <param name="defaultValue">The value that must be returned if there were no matches.</param>
        /// <returns>The single result or the default value.</returns>
        protected override TEntity FindSingleCore(Func <TEntity, bool> expression, string[] includePaths, DataSourceInfo dataSourceInfo, TEntity defaultValue)
        {
            MemoryStore <TEntity> memoryStore = this.SelectMemoryStore(dataSourceInfo);

            try {
                this.temporaryStorageLock.EnterReadLock();
                memoryStore.EnterReadLock();

                return(this.ConcatStorage(dataSourceInfo).SingleOrDefault(expression, defaultValue));
            }
            finally {
                memoryStore.ExitReadLock();

                if (this.temporaryStorageLock.IsReadLockHeld)
                {
                    this.temporaryStorageLock.ExitReadLock();
                }
            }
        }
Пример #3
0
        /// <summary>Finds the first entity that matches the expression or returns the default value if there were no matches.</summary>
        /// <param name="expression">The search-specification.</param>
        /// <param name="sortRules">The specification of the sort rules that must be applied. Use <see langword="null"/> to ignore the ordering.</param>
        /// <param name="includePaths">The dot-separated lists of related objects to return in the query results.</param>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        /// <param name="defaultValue">The value that must be returned if there were no matches.</param>
        /// <returns>The first result or the default value.</returns>
        protected override TEntity FindFirstCore(Func <TEntity, bool> expression, SortSpecifications <TEntity> sortRules, string[] includePaths, DataSourceInfo dataSourceInfo,
                                                 TEntity defaultValue)
        {
            MemoryStore <TEntity> memoryStore = this.SelectMemoryStore(dataSourceInfo);

            try {
                this.temporaryStorageLock.EnterReadLock();
                memoryStore.EnterReadLock();

                return(this.ConcatStorage(dataSourceInfo).OrderBy(sortRules).FirstOrDefault(expression, defaultValue));
            }
            finally {
                memoryStore.ExitReadLock();

                if (this.temporaryStorageLock.IsReadLockHeld)
                {
                    this.temporaryStorageLock.ExitReadLock();
                }
            }
        }
Пример #4
0
        /// <summary>Updates a collection of entities in the repository. Depending on the status of each entity, it is updated in the addition-cache or
        /// it is added to the update-cache.</summary>
        /// <param name="entities">The entities that contain the updated values.</param>
        /// <param name="dataSourceInfo">Information about the data source that may not have been set at an earlier stage. This parameter is not used.
        /// </param>
        /// <returns>The entities as they are stored in the repository.</returns>
        protected override IEnumerable <TEntity> UpdateEntitiesCore(IEnumerable <TEntity> entities, DataSourceInfo dataSourceInfo)
        {
            if (entities.Any(e => e.RecordId == 0))
            {
                throw new InvalidOperationException("Cannot update an entity whose identifier is zero.");
            }

            EntityEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();
            MemoryStore <TEntity>            memoryStore    = this.SelectMemoryStore(dataSourceInfo);

            IEnumerable <TEntity> addedEntities   = entities.Where(e => e.RecordId < 0);
            IEnumerable <TEntity> updatedEntities = entities.Where(e => e.RecordId > 0);

            this.temporaryStorageLock.EnterWriteLock();
            memoryStore.EnterReadLock();

            /* Make a copy of the caches. That way, if any thing goes wrong all the changes can be made undone */
            List <TEntity> tempAdditionCache = this.additionCache.ToList();
            List <TEntity> tempUpdateCache   = this.updateCache.ToList();
            List <TEntity> tempDeletionCache = this.deletionCache.ToList();

            List <TEntity> newlyAddedEntities     = new List <TEntity>();
            List <TEntity> currentUpdatedEntities = new List <TEntity>();

            try {
                foreach (TEntity addedEntity in addedEntities)
                {
                    /* If the entity is marked for addition, update the entity in the addition cache */
                    if (tempAdditionCache.Contains(addedEntity, entityComparer))
                    {
                        int     indexOfEntity    = tempAdditionCache.IndexOf(addedEntity, entityComparer);
                        TEntity repositoryEntity = tempAdditionCache[indexOfEntity];

                        /* Copy the  values of the updated entity into the cached entity */
                        repositoryEntity.CopyFrom(addedEntity);
                        newlyAddedEntities.Add(repositoryEntity);
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the addition-cache.");
                    }
                }

                foreach (TEntity updatedEntity in updatedEntities)
                {
                    if (memoryStore.Storage.Contains(updatedEntity, entityComparer))
                    {
                        /* If the entity is already marked for deletion, it can no longer be updated. */
                        if (tempDeletionCache.Contains(updatedEntity, entityComparer))
                        {
                            throw new InvalidOperationException("Cannot update the entity since it already marked for deletion.");
                        }

                        TEntity repositoryEntity;
                        if (tempUpdateCache.Contains(updatedEntity, entityComparer))
                        {
                            /* If the entity was already marked for update, replace it in the update cache */
                            int indexOfEntity = tempUpdateCache.IndexOf(updatedEntity, entityComparer);
                            repositoryEntity = tempUpdateCache[indexOfEntity];

                            /* Copy the  values of the updated entity into the cached entity */
                            repositoryEntity.CopyFrom(updatedEntity);
                        }
                        else
                        {
                            /* Retrieve the original version of the entity from the storage */
                            TEntity originalEntity = memoryStore.Storage[memoryStore.Storage.IndexOf(updatedEntity, entityComparer)];
                            /* Create a copy of the original entity to avoid any unwanted updates of the original entity */
                            repositoryEntity = originalEntity.CreateCopyOrClone();

                            /* Copy the  values of the updated entity into the (copy of) original entity */
                            repositoryEntity.CopyFrom(updatedEntity);
                            /* Store the updated entity in the update cache */
                            tempUpdateCache.Add(repositoryEntity);
                        }

                        currentUpdatedEntities.Add(repositoryEntity);
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the internal cache.");
                    }
                }

                /* Replace the original caches to complete the 'transaction' */
                this.additionCache = tempAdditionCache;
                this.updateCache   = tempUpdateCache;
                this.deletionCache = tempDeletionCache;

                if (this.SelectCloneDataSourceItems(dataSourceInfo))
                {
                    return(newlyAddedEntities.Concat(currentUpdatedEntities).Select(entity => ((ICloneable)entity).Clone() as TEntity).ToList());
                }
                else
                {
                    IEnumerable <TEntity> resultList = newlyAddedEntities.Concat(currentUpdatedEntities);
                    resultList.ForEach(entity => entities.Single(e => e.RecordId == entity.RecordId).CopyFrom(entity));
                    return(entities);
                }
            }
            finally {
                memoryStore.ExitReadLock();
                if (this.temporaryStorageLock.IsWriteLockHeld)
                {
                    this.temporaryStorageLock.ExitWriteLock();
                }
            }
        }
Пример #5
0
        /// <summary>Updates an entity in the storage.</summary>
        /// <param name="entity">The entity that must be updated.</param>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        /// <returns>The updated entity.</returns>
        protected override TEntity UpdateEntityCore(TEntity entity, DataSourceInfo dataSourceInfo)
        {
            if (entity.RecordId == 0)
            {
                throw new InvalidOperationException("Cannot update an entity whose identifier is zero.");
            }

            EntityEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();
            MemoryStore <TEntity>            memoryStore    = this.SelectMemoryStore(dataSourceInfo);

            try {
                /* First search the temporary storage */
                this.temporaryStorageLock.EnterWriteLock();
                memoryStore.EnterReadLock();

                if (entity.RecordId < 0)
                {
                    if (this.additionCache.Contains(entity, entityComparer))
                    {
                        int     indexOfEntity    = this.additionCache.IndexOf(entity, entityComparer);
                        TEntity repositoryEntity = this.additionCache[indexOfEntity];

                        /* Copy the  values of the updated entity into the cached entity */
                        repositoryEntity.CopyFrom(entity);

                        if (this.SelectCloneDataSourceItems(dataSourceInfo))
                        {
                            return(((ICloneable)repositoryEntity).Clone() as TEntity);
                        }
                        else
                        {
                            entity.CopyFrom(repositoryEntity);
                            return(entity);
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the addition-cache.");
                    }
                }
                else
                {
                    if (memoryStore.Storage.Contains(entity, entityComparer))
                    {
                        if (this.deletionCache.Contains(entity, entityComparer))
                        {
                            throw new InvalidOperationException("Cannot update the entity since it already marked for deletion.");
                        }

                        TEntity repositoryEntity;
                        if (this.updateCache.Contains(entity, entityComparer))
                        {
                            /* Retrieve the previous updated version of the entity from the cache */
                            int indexOfEntity = this.updateCache.IndexOf(entity, entityComparer);
                            repositoryEntity = this.updateCache[indexOfEntity];

                            /* Copy the  values of the updated entity into the cached entity */
                            repositoryEntity.CopyFrom(entity);
                        }
                        else
                        {
                            /* Retrieve the original version of the entity from the storage */
                            TEntity originalEntity = memoryStore.Storage[memoryStore.Storage.IndexOf(entity, entityComparer)];
                            /* Create a copy of the original entity to avoid any unwanted updates of the original entity */
                            repositoryEntity = originalEntity.CreateCopyOrClone();

                            /* Copy the  values of the updated entity into the (copy of) original entity */
                            repositoryEntity.CopyFrom(entity);
                            /* Store the updated entity in the update cache */
                            this.updateCache.Add(repositoryEntity);
                        }

                        /* Return an instance of TEntity that reflects the changes, but is disconnected from the instance that is stored in the cache
                         * (to avoid unwanted updates from outside the repository) */
                        if (this.SelectCloneDataSourceItems(dataSourceInfo))
                        {
                            return(((ICloneable)repositoryEntity).Clone() as TEntity);
                        }
                        else
                        {
                            entity.CopyFrom(repositoryEntity);
                            return(entity);
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the internal cache.");
                    }
                }
            }
            finally {
                memoryStore.ExitReadLock();
                if (this.temporaryStorageLock.IsWriteLockHeld)
                {
                    this.temporaryStorageLock.ExitWriteLock();
                }
            }
        }
Пример #6
0
        /// <summary>Removes a collection of entities from the repository. Depending on the status of each entity, it is removed from the addition-cache
        /// or it is added to the deletion-cache until it is saved using the <see cref="Repository{T}.SaveChanges()"/> method.</summary>
        /// <param name="entities">The entities that must be removed.</param>
        /// <param name="dataSourceInfo">Information about the data source that may not have been set at an earlier stage. This parameter is not used.
        /// </param>
        protected override void DeleteEntitiesCore(IEnumerable <TEntity> entities, DataSourceInfo dataSourceInfo)
        {
            if (entities.Any(e => e.RecordId == 0))
            {
                throw new InvalidOperationException("Cannot delete an entity whose identifier is zero.");
            }

            IEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();
            MemoryStore <TEntity>       memoryStore    = this.SelectMemoryStore(dataSourceInfo);

            this.temporaryStorageLock.EnterWriteLock();
            memoryStore.EnterReadLock();

            IEnumerable <TEntity> addedEntities    = entities.Where(e => e.RecordId < 0);
            IEnumerable <TEntity> existingEntities = entities.Where(e => e.RecordId > 0);

            /* Make a copy of the caches. That way, if any thing goes wrong all the changes can be made undone */
            List <TEntity> tempAdditionCache = this.additionCache.ToList();
            List <TEntity> tempUpdateCache   = this.updateCache.ToList();
            List <TEntity> tempDeletionCache = this.deletionCache.ToList();

            try {
                foreach (TEntity addedEntity in addedEntities)
                {
                    /* If the ID is negative, it should be marked for addition */
                    if (tempAdditionCache.Contains(addedEntity, entityComparer))
                    {
                        tempAdditionCache.Remove(addedEntity, entityComparer);
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the memory.");
                    }
                }

                foreach (TEntity existingEntity in existingEntities)
                {
                    /* If the entity was marked for update, remove that mark */
                    if (tempUpdateCache.Contains(existingEntity, entityComparer))
                    {
                        tempUpdateCache.Remove(existingEntity, entityComparer);
                    }

                    /* If the entity exists in the original data source and has not yet been marked for deletion, mark it now */
                    if (memoryStore.Storage.Contains(existingEntity, entityComparer))
                    {
                        if (!tempDeletionCache.Contains(existingEntity, entityComparer))
                        {
                            tempDeletionCache.Add(existingEntity);
                        }
                        else
                        {
                            throw new InvalidOperationException("Cannot delete the same entity more then once.");
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the internal cache.");
                    }
                }

                /* Replace the original caches to complete the 'transaction' */
                this.additionCache = tempAdditionCache;
                this.updateCache   = tempUpdateCache;
                this.deletionCache = tempDeletionCache;
            }
            finally {
                memoryStore.ExitReadLock();
                if (this.temporaryStorageLock.IsWriteLockHeld)
                {
                    this.temporaryStorageLock.ExitWriteLock();
                }
            }
        }
Пример #7
0
        /// <summary>Deletes the entity from the storage.</summary>
        /// <param name="entity">The entity that must be removed.</param>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        protected override void DeleteEntityCore(TEntity entity, DataSourceInfo dataSourceInfo)
        {
            if (entity.RecordId == 0)
            {
                throw new InvalidOperationException("Cannot delete an entity whose identifier is zero.");
            }

            IEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();

            MemoryStore <TEntity> memoryStore = this.SelectMemoryStore(dataSourceInfo);

            try {
                /* First search the temporary storage */
                this.temporaryStorageLock.EnterWriteLock();
                memoryStore.EnterReadLock();

                if (entity.RecordId < 0)
                {
                    /* If the ID is negative, it should be marked for addition */
                    if (this.additionCache.Contains(entity, entityComparer))
                    {
                        this.additionCache.Remove(entity, entityComparer);
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the memory.");
                    }
                }
                else
                {
                    /* If the entity was marked for update, remove that mark */
                    if (this.updateCache.Contains(entity, entityComparer))
                    {
                        this.updateCache.Remove(entity, entityComparer);
                    }

                    /* If the entity exists in the original data source and has not yet been marked for deletion, mark it now */
                    if (memoryStore.Storage.Contains(entity, entityComparer))
                    {
                        if (!this.deletionCache.Contains(entity, entityComparer))
                        {
                            this.deletionCache.Add(entity);
                        }
                        else
                        {
                            throw new InvalidOperationException("Cannot delete the same entity more then once.");
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Could not find the entity in the memory.");
                    }
                }
            }
            finally {
                memoryStore.ExitReadLock();

                if (this.temporaryStorageLock.IsWriteLockHeld)
                {
                    this.temporaryStorageLock.ExitWriteLock();
                }
            }
        }