예제 #1
0
        /**
         * This method allows for a concurrency-safe pattern to check for the existence of a given entity and, if it
         * does not exist to create it, or if it does exist, to update it.
         *
         * This is concurrency-safe as it ensures that any two concurrent importer processes that are trying to create
         * or update the same entity type with the same ID will not be able to do so at the same time.  Rather, the
         * first thread to reach this code will acquire a lock and prevent the second thread from being able to check
         * for the existence of the entity until the first thread has finished creating it.  At this point, the second
         * thread is freed up to check if the entity already exists, which by this point, it will.
         */
        private Task <TEntity> CreateOrUpdateWithExclusiveLock <TEntity, TMessageObject>(
            string entityName,
            StatisticsDbContext statisticsDbContext,
            TMessageObject objectFromMessage,
            Guid entityId,
            TEntity entityToCreate)
            where TEntity : class
            where TMessageObject : class
        {
            var typeName = typeof(TEntity).Name;

            return(DbUtils.ExecuteWithExclusiveLock(
                       statisticsDbContext,
                       $"CreateOrUpdate{typeName}-{entityId}",
                       async(context) =>
            {
                _logger.LogInformation(
                    $"Checking for existence of {typeName} \"{entityName}\"");

                var existing = await statisticsDbContext.Set <TEntity>().FindAsync(entityId);

                if (existing == null)
                {
                    _logger.LogInformation($"Creating {typeName} \"{entityName}\"");
                    TEntity created = (await statisticsDbContext.Set <TEntity>().AddAsync(entityToCreate)).Entity;
                    await statisticsDbContext.SaveChangesAsync();
                    return created;
                }

                _logger.LogInformation($"{typeName} \"{entityName}\" already exists - updating");
                TEntity mappedEntity = _mapper.Map(objectFromMessage, existing);
                TEntity updated = statisticsDbContext.Set <TEntity>().Update(mappedEntity).Entity;
                await statisticsDbContext.SaveChangesAsync();
                return updated;
            }));
        }
예제 #2
0
 protected DbSet <TEntity> DbSet()
 {
     return(_context.Set <TEntity>());
 }