Exemplo n.º 1
0
        /// <summary>Adds the entity to the storage.</summary>
        /// <param name="entity">The entity that must be added.</param>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        /// <returns>The entity with the updated recordID.</returns>
        protected override TEntity AddEntityCore(TEntity entity, DataSourceInfo dataSourceInfo)
        {
            EntityEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();

            try {
                this.temporaryStorageLock.EnterWriteLock();

                if (entity.RecordId > 0)
                {
                    /* The entity already has an ID which suggests that it came from the original datasource */
                    if (this.deletionCache.Contains(entity, entityComparer))
                    {
                        /* The entity has been marked for deletion, undelete it... */
                        this.deletionCache.Remove(entity, entityComparer);
                        /* ...and mark it as updated in case any of the fields have been altered. */
                        TEntity repositoryEntity = entity.CreateCopyOrClone();
                        this.updateCache.Add(repositoryEntity);
                        if (this.SelectCloneDataSourceItems(dataSourceInfo))
                        {
                            return(((ICloneable)repositoryEntity).Clone() as TEntity);
                        }
                        else
                        {
                            entity.CopyFrom(repositoryEntity);
                            return(entity);
                        }
                    }
                }

                /* The entity is either new or came from another data source */
                /* Determine the new temporary ID for the entity */
                int newRecordId = -1;
                if (this.additionCache.Count > 0)
                {
                    newRecordId = this.additionCache.Min(t => t.RecordId) - 1;
                }

                TEntity copyOfEntity = entity.CreateCopyOrClone();
                copyOfEntity.RecordId = newRecordId;

                /* Add it to the addition cache */
                this.additionCache.Add(copyOfEntity);

                if (this.SelectCloneDataSourceItems(dataSourceInfo))
                {
                    return(((ICloneable)copyOfEntity).Clone() as TEntity);
                }
                else
                {
                    entity.CopyFrom(copyOfEntity);
                    return(entity);
                }
            }
            finally {
                if (this.temporaryStorageLock.IsWriteLockHeld)
                {
                    this.temporaryStorageLock.ExitWriteLock();
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>Initializes a new instance of the <see cref="XmlFileRepository{TEntity}"/> class using the specified <see cref="DataSourceInfo"/>.
        /// </summary>
        /// <param name="dataSourceInfo">The data source information that must be used to access the source file.</param>
        public XmlFileRepository(DataSourceInfo dataSourceInfo)
            : base(dataSourceInfo)
        {
            XmlAttributeOverrides overrides = ConstructAttributeOverrides();

            this.serializer = new XmlSerializer(typeof(List <TEntity>), overrides);
        }
Exemplo n.º 3
0
 /// <summary>Selects the <see cref="SaveGraph"/> from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The <see cref="SaveGraph"/> that is stored in the data source information or <see langword="null"/> if the <see cref="SaveGraph"/> could not be found.</returns>
 public static bool SelectSaveGraph(DataSourceInfo dataSourceInfo)
 {
     if (IsSaveGraphSpecified(dataSourceInfo))
     {
         return((bool)dataSourceInfo[SaveGraphKey]);
     }
     else
     {
         return(DatabaseSourceInfo.DefaultSaveGraph);
     }
 }
Exemplo n.º 4
0
 /// <summary>Selects the <see cref="DbContext"/> from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The <see cref="DbContext"/> that is stored in the data source information or <see langword="null"/> if the <see cref="DbContext"/> could not be found.</returns>
 public static DbContext SelectDbContext(DataSourceInfo dataSourceInfo)
 {
     if (IsDbContextSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[DbContextKey] as DbContext);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 5
0
 /// <summary>Selects the source file's encoding from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The value that is stored in the data source information or <see langword="null"/> if the value could not be found.</returns>
 public static Encoding SelectSourceFileEncoding(DataSourceInfo dataSourceInfo)
 {
     if (IsSourceFileEncodingSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[SourceFileEncodingKey] as Encoding);
     }
     else
     {
         return(DefaultSourceFileEncoding);
     }
 }
Exemplo n.º 6
0
 /// <summary>Selects the change complete timeout from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The value that is stored in the data source information or the default value if the flag could not be found.</returns>
 public static int SelectChangeCompleteTimeout(DataSourceInfo dataSourceInfo)
 {
     if (IsChangeCompleteTimeoutSpecified(dataSourceInfo))
     {
         return((int)dataSourceInfo[ChangeCompleteTimeoutKey]);
     }
     else
     {
         return(DefaultChangeCompleteTimeout);
     }
 }
Exemplo n.º 7
0
 /// <summary>Selects the monitor-flag from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The monitor-flag that is stored in the data source information or <see langword="true"/> if the flag could not be found.</returns>
 public static bool SelectMonitorSourceFile(DataSourceInfo dataSourceInfo)
 {
     if (IsMonitorSourceFileSpecified(dataSourceInfo))
     {
         return((bool)dataSourceInfo[MonitorSourceFileKey]);
     }
     else
     {
         return(DefaultMonitorSourceFile);
     }
 }
Exemplo n.º 8
0
 /// <summary>Selects the 'clone data source items'-flag from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The flag that is stored in the data source information or <see langword="false"/> if the flag could not be found.</returns>
 public static bool SelectCloneDataSourceItems(DataSourceInfo dataSourceInfo)
 {
     if (IsCloneDataSourceItemsSpecified(dataSourceInfo))
     {
         return((bool)dataSourceInfo[CloneDataSourceItemsKey]);
     }
     else
     {
         return(DefaultCloneDataSourceItems);
     }
 }
Exemplo n.º 9
0
 /// <summary>Selects the MemoryStore from the specified data source information.</summary>
 /// <typeparam name="T">The type of object that is stored in the memory store.</typeparam>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The MemoryStore that is stored in the data source information or <see langword="null"/> if the MemoryStore could not be found.
 /// </returns>
 public static MemoryStore <T> SelectMemoryStore <T>(DataSourceInfo dataSourceInfo) where T : class
 {
     if (IsMemoryStoreSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[MemoryStoreKey] as MemoryStore <T>);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 10
0
 /// <summary>Selects the remote address from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The value that is stored in the data source information or <see langword="null"/> if the value could not be found.</returns>
 public static EndpointAddress SelectRemoteAddress(DataSourceInfo dataSourceInfo)
 {
     if (IsRemoteAddressSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[RemoteAddressKey] as EndpointAddress);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 11
0
 /// <summary>Selects the binding from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The value that is stored in the data source information or <see langword="null"/> if the value could not be found.</returns>
 public static Binding SelectBinding(DataSourceInfo dataSourceInfo)
 {
     if (IsBindingSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[BindingKey] as Binding);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 12
0
 /// <summary>Selects the MemoryStore that must be used. If the specified DataSourceInfo contains a valid MemoryStore, it is used; otherwise the
 /// value of the property 'MemoryStore' is used.</summary>
 /// <param name="dataSourceInfo">Any information regarding the data store that is used as data source.</param>
 /// <returns>The MemoryStore that must be used.</returns>
 private MemoryStore <TEntity> SelectMemoryStore(DataSourceInfo dataSourceInfo)
 {
     if (MemorySourceInfo.IsMemoryStoreSpecified(dataSourceInfo))
     {
         return(MemorySourceInfo.SelectMemoryStore <TEntity>(dataSourceInfo));
     }
     else
     {
         return(this.MemoryStore);
     }
 }
Exemplo n.º 13
0
 /// <summary>Selects the endpoint configuration from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The value that is stored in the data source information or <see langword="null"/> if the value could not be found.</returns>
 public static string SelectEndpointConfigurationName(DataSourceInfo dataSourceInfo)
 {
     if (IsEndpointConfigurationNameSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[EndpointConfigurationNameKey] as string);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 14
0
 /// <summary>Selects the source FileInfo from the specified data source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns>The FileInfo that is stored in the data source information or <see langword="null"/> if the FileInfo could not be found.</returns>
 public static FileInfo SelectSourceFileInfo(DataSourceInfo dataSourceInfo)
 {
     if (IsSourceFileInfoSpecified(dataSourceInfo))
     {
         return(dataSourceInfo[SourceFileInfoKey] as FileInfo);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 15
0
        /// <summary>Initializes a new instance of the <see cref="MemoryRepository{TEntity}"/> class using the specified <see cref="DataSourceInfo"/>.
        /// </summary>
        /// <param name="dataSourceInfo">The data source information that must be used to access the data source.</param>
        /// <exception cref="InvalidOperationException"><paramref name="dataSourceInfo"/> does not specify a valid <see cref="Enkoni.Framework.Entities.MemoryStore{T}"/>.
        /// </exception>
        public MemoryRepository(DataSourceInfo dataSourceInfo)
            : base(dataSourceInfo)
        {
            /* Initializes the internal collections */
            this.additionCache = new List <TEntity>();
            this.updateCache   = new List <TEntity>();
            this.deletionCache = new List <TEntity>();

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

            if (this.MemoryStore == null)
            {
                throw new InvalidOperationException("The memory store is mandatory.");
            }
        }
Exemplo n.º 16
0
        /// <summary>Concatenates the global caches and local cache into one complete and up-to-date cache.</summary>
        /// <param name="dataSourceInfo">Any information regarding the data store that is used as data source.</param>
        /// <returns>The concatenated cache-values.</returns>
        private IEnumerable <TEntity> ConcatStorage(DataSourceInfo dataSourceInfo)
        {
            EntityEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();

            IEnumerable <TEntity> totalCache = this.SelectMemoryStore(dataSourceInfo).Storage;

            if (this.SelectCloneDataSourceItems(dataSourceInfo))
            {
                totalCache = totalCache.Select(t => ((ICloneable)t).Clone() as TEntity);
            }

            totalCache = totalCache.Concat(this.additionCache);
            /*...then remove the entities that were updated from the basic cache and replace them with the updated versions... */
            totalCache = totalCache.Except(this.updateCache, entityComparer).Concat(this.updateCache);
            /* ...finally, remove the deleted entities */
            totalCache = totalCache.Except(this.deletionCache, entityComparer);

            return(totalCache.OrderBy(t => t.RecordId));
        }
Exemplo n.º 17
0
        /// <summary>Initializes a new instance of the <see cref="ServiceRepository{TEntity}"/> class using the specified <see cref="DataSourceInfo"/>.
        /// </summary>
        /// <param name="dataSourceInfo">The data source information that must be used to access the source file.</param>
        protected ServiceRepository(DataSourceInfo dataSourceInfo)
            : base(dataSourceInfo)
        {
            /* Determine if the supported properties have been specified */
            if (ServiceSourceInfo.IsEndpointConfigurationNameSpecified(dataSourceInfo))
            {
                this.EndpointConfigurationName = ServiceSourceInfo.SelectEndpointConfigurationName(dataSourceInfo);
            }

            if (ServiceSourceInfo.IsRemoteAddressSpecified(dataSourceInfo))
            {
                this.RemoteAddress = ServiceSourceInfo.SelectRemoteAddress(dataSourceInfo);
            }

            if (ServiceSourceInfo.IsBindingSpecified(dataSourceInfo))
            {
                this.Binding = ServiceSourceInfo.SelectBinding(dataSourceInfo);
            }
        }
Exemplo n.º 18
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();
                }
            }
        }
Exemplo n.º 19
0
 /// <summary>Determines if the remote address is specified in the source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns><see langword="true"/> if the value is defined; <see langword="false"/> otherwise.</returns>
 public static bool IsRemoteAddressSpecified([ValidatedNotNull] DataSourceInfo dataSourceInfo)
 {
     return(dataSourceInfo != null && dataSourceInfo.IsValueSpecified(RemoteAddressKey));
 }
Exemplo n.º 20
0
 /// <summary>Determines if the endpoint configuration is specified in the source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns><see langword="true"/> if the value is defined; <see langword="false"/> otherwise.</returns>
 public static bool IsEndpointConfigurationNameSpecified([ValidatedNotNull] DataSourceInfo dataSourceInfo)
 {
     return(dataSourceInfo != null && dataSourceInfo.IsValueSpecified(EndpointConfigurationNameKey));
 }
Exemplo n.º 21
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();
                }
            }
        }
Exemplo n.º 22
0
 /// <summary>Determines if the 'clone data source items'-flag is specified in the source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns><see langword="true"/> if the flag is defined; <see langword="false"/> otherwise.</returns>
 public static bool IsCloneDataSourceItemsSpecified([ValidatedNotNull] DataSourceInfo dataSourceInfo)
 {
     return(dataSourceInfo != null && dataSourceInfo.IsValueSpecified(CloneDataSourceItemsKey));
 }
Exemplo n.º 23
0
 /// <summary>Determines if the binding is specified in the source information.</summary>
 /// <param name="dataSourceInfo">The data source information that is queried.</param>
 /// <returns><see langword="true"/> if the value is defined; <see langword="false"/> otherwise.</returns>
 public static bool IsBindingSpecified([ValidatedNotNull] DataSourceInfo dataSourceInfo)
 {
     return(dataSourceInfo != null && dataSourceInfo.IsValueSpecified(BindingKey));
 }
Exemplo n.º 24
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();
                }
            }
        }
Exemplo n.º 25
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();
                }
            }
        }
Exemplo n.º 26
0
        /// <summary>Adds a collection of new entities to the repository. They are added to the addition cache until it is saved using the
        /// <see cref="Repository{T}.SaveChanges()"/> method. A temporary (negative) RecordID is assigned to the entities. This will be reset when the entity is
        /// saved.</summary>
        /// <param name="entities">The entities that must be added.</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 were added to the repository.</returns>
        protected override IEnumerable <TEntity> AddEntitiesCore(IEnumerable <TEntity> entities, DataSourceInfo dataSourceInfo)
        {
            EntityEqualityComparer <TEntity> entityComparer = new EntityEqualityComparer <TEntity>();

            /* Place the entities in a list to keep track of the entities that have been handled */
            List <TEntity> unhandledEntities = entities.ToList();

            this.temporaryStorageLock.EnterWriteLock();

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

            List <TEntity> updatedEntities = new List <TEntity>();
            List <TEntity> addedEntities   = new List <TEntity>();

            Dictionary <TEntity, TEntity> handledEntities = new Dictionary <TEntity, TEntity>();

            try {
                if (entities.Any(e => e.RecordId > 0))
                {
                    IEnumerable <TEntity> existingEntities = entities.Where(e => e.RecordId > 0);
                    ReferenceEqualityComparer <TEntity> referenceComparer = new ReferenceEqualityComparer <TEntity>();
                    /* At least some of the entities already have an ID which suggests that they came from the original datasource */
                    foreach (TEntity existingEntity in existingEntities)
                    {
                        if (tempDeletionCache.Contains(existingEntity, entityComparer))
                        {
                            /* The entity has been marked for deletion, undelete it... */
                            tempDeletionCache.Remove(existingEntity, entityComparer);
                            /* ...and mark it as updated in case any of the fields have been altered. */
                            TEntity repositoryEntity = existingEntity.CreateCopyOrClone();
                            tempUpdateCache.Add(repositoryEntity);
                            updatedEntities.Add(repositoryEntity);

                            handledEntities.Add(existingEntity, repositoryEntity);
                            bool removeResult = unhandledEntities.Remove(existingEntity, referenceComparer);
                            Debug.Assert(removeResult, "Somehow the result could not be removed from the collection of handled entities.");
                        }
                    }
                }

                if (unhandledEntities.Count > 0)
                {
                    /* At least some of the entities are either new or came from another data source */
                    /* Determine the new temporary ID for the entities */
                    int newRecordId = -1;
                    if (tempAdditionCache.Count > 0)
                    {
                        newRecordId = tempAdditionCache.Min(t => t.RecordId) - 1;
                    }

                    foreach (TEntity unhandledEntity in unhandledEntities)
                    {
                        TEntity copyOfEntity = unhandledEntity.CreateCopyOrClone();

                        copyOfEntity.RecordId = newRecordId;
                        --newRecordId;
                        /* Add it to the addition cache */
                        tempAdditionCache.Add(copyOfEntity);
                        addedEntities.Add(copyOfEntity);
                        handledEntities.Add(unhandledEntity, copyOfEntity);
                    }
                }

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

                if (this.SelectCloneDataSourceItems(dataSourceInfo))
                {
                    return(addedEntities.Concat(updatedEntities).Select(entity => ((ICloneable)entity).Clone() as TEntity).ToList());
                }
                else
                {
                    handledEntities.ForEach(kvp => kvp.Key.CopyFrom(kvp.Value));
                    return(entities);
                }
            }
            finally {
                this.temporaryStorageLock.ExitWriteLock();
            }
        }
Exemplo n.º 27
0
 /// <summary>Resets the repository by undoing any unsaved changes.</summary>
 /// <param name="dataSourceInfo">Information about the data source that may not have been set at an earlier stage.</param>
 protected override void ResetCore(DataSourceInfo dataSourceInfo)
 {
     this.additionCache.Clear();
     this.deletionCache.Clear();
     this.updateCache.Clear();
 }
Exemplo n.º 28
0
        /// <summary>Merges the temporary storage with the global storage.</summary>
        /// <param name="dataSourceInfo">The parameter is not used.</param>
        protected override void SaveChangesCore(DataSourceInfo dataSourceInfo)
        {
            MemoryStore <TEntity> memoryStore = this.SelectMemoryStore(dataSourceInfo);

            try {
                /* Make sure no one has access to the global and local storage */
                memoryStore.EnterWriteLock();
                this.temporaryStorageLock.EnterWriteLock();

                /* First, check if all the updated entities still exist in the global storage */
                Dictionary <int, TEntity> updatedEntities = new Dictionary <int, TEntity>();
                foreach (TEntity entity in this.updateCache)
                {
                    var storedEntity = memoryStore.Storage.Select((item, index) => new { Entity = item, Index = index })
                                       .FirstOrDefault(a => a.Entity.RecordId == entity.RecordId);
                    if (storedEntity == null)
                    {
                        throw new InvalidOperationException(
                                  string.Format(CultureInfo.CurrentCulture, "Cannot update entity {0} since it does not exist in the global storage", entity.RecordId));
                    }
                    else
                    {
                        updatedEntities.Add(storedEntity.Index, entity);
                    }
                }

                /* Then, check if all the deleted entities still exist in the global storage */
                Dictionary <int, TEntity> deletedEntities = new Dictionary <int, TEntity>();
                foreach (TEntity entity in this.deletionCache)
                {
                    var storedEntity = memoryStore.Storage.Select((item, index) => new { Entity = item, Index = index })
                                       .FirstOrDefault(a => a.Entity.RecordId == entity.RecordId);
                    if (storedEntity == null)
                    {
                        throw new InvalidOperationException(
                                  string.Format(CultureInfo.CurrentCulture, "Cannot delete entity {0} since it does not exist in the global storage", entity.RecordId));
                    }
                    else
                    {
                        deletedEntities.Add(storedEntity.Index, entity);
                    }
                }

                /* All the pre-checks have been completed, start the saving */
                /* First, perform the updates */
                foreach (KeyValuePair <int, TEntity> updatedEntity in updatedEntities)
                {
                    if (this.SelectCloneDataSourceItems(dataSourceInfo))
                    {
                        memoryStore.Storage[updatedEntity.Key] = ((ICloneable)updatedEntity.Value).Clone() as TEntity;
                    }
                    else
                    {
                        memoryStore.Storage[updatedEntity.Key] = updatedEntity.Value;
                    }
                }

                /* Then perform the deletions */
                int iteration = 0;
                foreach (KeyValuePair <int, TEntity> deletedEntity in deletedEntities.OrderBy(kvp => kvp.Key))
                {
                    memoryStore.Storage.RemoveAt(deletedEntity.Key - iteration);
                    ++iteration;
                }

                /* Then apply new identifiers to the new entities */
                int startId = memoryStore.Storage.DefaultIfEmpty(new TEntity {
                    RecordId = 0
                }).Max(t => t.RecordId) + 1;
                this.ApplyIdentifiers(this.additionCache, startId);

                /* Then add the added entities to the global storage */
                foreach (TEntity addedEntity in this.additionCache)
                {
                    if (this.SelectCloneDataSourceItems(dataSourceInfo))
                    {
                        memoryStore.Storage.Add(((ICloneable)addedEntity).Clone() as TEntity);
                    }
                    else
                    {
                        memoryStore.Storage.Add(addedEntity);
                    }
                }

                /* Finally, clear the local storage */
                this.additionCache.Clear();
                this.updateCache.Clear();
                this.deletionCache.Clear();
            }
            finally {
                memoryStore.ExitWriteLock();
                this.temporaryStorageLock.ExitWriteLock();
            }
        }
Exemplo n.º 29
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();
                }
            }
        }
Exemplo n.º 30
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();
                }
            }
        }