public virtual async Task DeleteAsync(TId id)
        {
            _logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}').");

            if (!IsNull(_hookExecutor))
            {
                var entity = _resourceFactory.CreateInstance <TResource>();
                entity.Id = id;

                _hookExecutor.BeforeDelete(AsList(entity), ResourcePipeline.Delete);
            }

            var succeeded = await _repository.DeleteAsync(id);

            if (!succeeded)
            {
                string resourceId = TypeHelper.GetResourceStringId <TResource, TId>(id, _resourceFactory);
                throw new ResourceNotFoundException(resourceId, _currentRequestResource.ResourceName);
            }

            if (!IsNull(_hookExecutor))
            {
                var entity = _resourceFactory.CreateInstance <TResource>();
                entity.Id = id;

                _hookExecutor.AfterDelete(AsList(entity), ResourcePipeline.Delete, succeeded);
            }
        }
        /// <inheritdoc />
        public virtual async Task DeleteAsync(TId id)
        {
            _traceWriter.LogMethodStart(new { id });

            if (_hookExecutor != null)
            {
                var resource = _resourceFactory.CreateInstance <TResource>();
                resource.Id = id;

                _hookExecutor.BeforeDelete(AsList(resource), ResourcePipeline.Delete);
            }

            var succeeded = await _repository.DeleteAsync(id);

            if (_hookExecutor != null)
            {
                var resource = _resourceFactory.CreateInstance <TResource>();
                resource.Id = id;

                _hookExecutor.AfterDelete(AsList(resource), ResourcePipeline.Delete, succeeded);
            }

            if (!succeeded)
            {
                AssertPrimaryResourceExists(null);
            }
        }
        public virtual async Task DeleteAsync(TId id)
        {
            _logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}').");

            if (_hookExecutor != null)
            {
                var resource = _resourceFactory.CreateInstance <TResource>();
                resource.Id = id;

                _hookExecutor.BeforeDelete(AsList(resource), ResourcePipeline.Delete);
            }

            var succeeded = await _repository.DeleteAsync(id);

            if (_hookExecutor != null)
            {
                var resource = _resourceFactory.CreateInstance <TResource>();
                resource.Id = id;

                _hookExecutor.AfterDelete(AsList(resource), ResourcePipeline.Delete, succeeded);
            }

            if (!succeeded)
            {
                AssertPrimaryResourceExists(null);
            }
        }
示例#4
0
        /// <inheritdoc />
        public virtual Task <TResource> GetForCreateAsync(TId id, CancellationToken cancellationToken)
        {
            var resource = _resourceFactory.CreateInstance <TResource>();

            resource.Id = id;

            return(Task.FromResult(resource));
        }
示例#5
0
        public void BeforeReadSingle <TResource, TId>(TId id, ResourcePipeline pipeline)
            where TResource : class, IIdentifiable <TId>
        {
            var temporaryResource = _resourceFactory.CreateInstance <TResource>();

            temporaryResource.Id = id;

            _resourceHookExecutor.BeforeRead <TResource>(pipeline, temporaryResource.StringId);
        }
        /// <inheritdoc />
        public virtual async Task <bool> DeleteAsync(TId id)
        {
            _logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}').");

            var resourceToDelete = _resourceFactory.CreateInstance <TResource>();

            resourceToDelete.Id = id;

            var resourceFromCache = _dbContext.GetTrackedEntity(resourceToDelete);

            if (resourceFromCache != null)
            {
                resourceToDelete = resourceFromCache;
            }
            else
            {
                _dbContext.Attach(resourceToDelete);
            }

            _dbContext.Remove(resourceToDelete);

            try
            {
                await _dbContext.SaveChangesAsync();

                return(true);
            }
            catch (DbUpdateConcurrencyException)
            {
                return(false);
            }
        }
        private string DeObfuscateStringId(Type resourceType, string stringId)
        {
            var tempResource = _resourceFactory.CreateInstance(resourceType);

            tempResource.StringId = stringId;
            return(tempResource.GetTypedId().ToString());
        }
        public static string GetResourceStringId <TResource, TId>(TId id, IResourceFactory resourceFactory) where TResource : class, IIdentifiable <TId>
        {
            TResource tempResource = resourceFactory.CreateInstance <TResource>();

            tempResource.Id = id;
            return(tempResource.StringId);
        }
        public static object ConvertStringIdToTypedId(Type resourceType, string stringId, IResourceFactory resourceFactory)
        {
            var tempResource = (IIdentifiable)resourceFactory.CreateInstance(resourceType);

            tempResource.StringId = stringId;
            return(GetResourceTypedId(tempResource));
        }
        /// <summary>
        /// Traverses through the provided resource and sets the value of the relationship on the other side of the through type.
        /// In the example described above, this would be the value of "Articles.ArticleTags.Tag".
        /// </summary>
        public override void SetValue(object resource, object newValue, IResourceFactory resourceFactory)
        {
            if (resource == null)
            {
                throw new ArgumentNullException(nameof(resource));
            }
            if (resourceFactory == null)
            {
                throw new ArgumentNullException(nameof(resourceFactory));
            }

            base.SetValue(resource, newValue, resourceFactory);

            if (newValue == null)
            {
                ThroughProperty.SetValue(resource, null);
            }
            else
            {
                List <object> throughResources = new List <object>();
                foreach (IIdentifiable identifiable in (IEnumerable)newValue)
                {
                    object throughResource = resourceFactory.CreateInstance(ThroughType);
                    LeftProperty.SetValue(throughResource, resource);
                    RightProperty.SetValue(throughResource, identifiable);
                    throughResources.Add(throughResource);
                }

                var typedCollection = TypeHelper.CopyToTypedCollection(throughResources, ThroughProperty.PropertyType);
                ThroughProperty.SetValue(resource, typedCollection);
            }
        }
        /// <summary>
        /// Creates a new placeholder resource, assigns the specified ID, adds it to the change tracker
        /// in <see cref="EntityState.Unchanged"/> state and registers it for detachment.
        /// </summary>
        public TResource CreateForId <TResource, TId>(TId id)
            where TResource : IIdentifiable <TId>
        {
            var placeholderResource = _resourceFactory.CreateInstance <TResource>();

            placeholderResource.Id = id;

            return(CaptureExisting(placeholderResource));
        }
示例#12
0
        /// <inheritdoc />
        public virtual async Task <TResource> CreateAsync(TResource resource, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new { resource });
            if (resource == null)
            {
                throw new ArgumentNullException(nameof(resource));
            }

            _resourceChangeTracker.SetRequestedAttributeValues(resource);

            var defaultResource = _resourceFactory.CreateInstance <TResource>();

            defaultResource.Id = resource.Id;

            _resourceChangeTracker.SetInitiallyStoredAttributeValues(defaultResource);

            _hookExecutor.BeforeCreate(resource);

            try
            {
                await _repositoryAccessor.CreateAsync(resource, cancellationToken);
            }
            catch (DataStoreUpdateException)
            {
                var existingResource = await TryGetPrimaryResourceByIdAsync(resource.Id, TopFieldSelection.OnlyIdAttribute, cancellationToken);

                if (existingResource != null)
                {
                    throw new ResourceAlreadyExistsException(resource.StringId, _request.PrimaryResource.PublicName);
                }

                await AssertResourcesToAssignInRelationshipsExistAsync(resource, cancellationToken);

                throw;
            }

            var resourceFromDatabase = await TryGetPrimaryResourceByIdAsync(resource.Id, TopFieldSelection.WithAllAttributes, cancellationToken);

            AssertPrimaryResourceExists(resourceFromDatabase);

            _hookExecutor.AfterCreate(resourceFromDatabase);

            _resourceChangeTracker.SetFinallyStoredAttributeValues(resourceFromDatabase);

            bool hasImplicitChanges = _resourceChangeTracker.HasImplicitChanges();

            if (!hasImplicitChanges)
            {
                return(null);
            }

            _hookExecutor.OnReturnSingle(resourceFromDatabase, ResourcePipeline.Post);
            return(resourceFromDatabase);
        }
        /// <summary>
        /// Creates an instance of the referenced type in <paramref name="data"/>
        /// and sets its attributes and relationships
        /// </summary>
        /// <param name="data"></param>
        /// <returns>The parsed entity</returns>
        private IIdentifiable ParseResourceObject(ResourceObject data)
        {
            var resourceContext = _contextProvider.GetResourceContext(data.Type);

            if (resourceContext == null)
            {
                throw new InvalidRequestBodyException("Payload includes unknown resource type.",
                                                      $"The resource '{data.Type}' is not registered on the resource graph. " +
                                                      "If you are using Entity Framework, make sure the DbSet matches the expected resource name. " +
                                                      "If you have manually registered the resource, check that the call to AddResource correctly sets the public name.", null);
            }

            var entity = (IIdentifiable)_resourceFactory.CreateInstance(resourceContext.ResourceType);

            entity = SetAttributes(entity, data.Attributes, resourceContext.Attributes);
            entity = SetRelationships(entity, data.Relationships, resourceContext.Relationships);

            if (data.Id != null)
            {
                entity.StringId = data.Id;
            }

            return(entity);
        }
        private async Task UpdateManyToManyAsync(IIdentifiable parent, HasManyThroughAttribute relationship, IEnumerable <string> relationshipIds)
        {
            // we need to create a transaction for the HasManyThrough case so we can get and remove any existing
            // through resources and only commit if all operations are successful
            var transaction = await _context.GetCurrentOrCreateTransactionAsync();

            // ArticleTag
            ParameterExpression parameter = Expression.Parameter(relationship.ThroughType);
            // ArticleTag.ArticleId
            Expression idMember = Expression.Property(parameter, relationship.LeftIdProperty);
            // article.Id
            var        parentId = TypeHelper.ConvertType(parent.StringId, relationship.LeftIdProperty.PropertyType);
            Expression target   = Expression.Constant(parentId);
            // ArticleTag.ArticleId.Equals(article.Id)
            Expression callEquals = Expression.Call(idMember, "Equals", null, target);
            var        lambda     = Expression.Lambda <Func <TRelatedResource, bool> >(callEquals, parameter);
            // TODO: we shouldn't need to do this instead we should try updating the existing?
            // the challenge here is if a composite key is used, then we will fail to
            // create due to a unique key violation
            var oldLinks = _context
                           .Set <TRelatedResource>()
                           .Where(lambda.Compile())
                           .ToList();

            _context.RemoveRange(oldLinks);

            var newLinks = relationshipIds.Select(x =>
            {
                var link = _resourceFactory.CreateInstance(relationship.ThroughType);
                relationship.LeftIdProperty.SetValue(link, TypeHelper.ConvertType(parentId, relationship.LeftIdProperty.PropertyType));
                relationship.RightIdProperty.SetValue(link, TypeHelper.ConvertType(x, relationship.RightIdProperty.PropertyType));
                return(link);
            });

            _context.AddRange(newLinks);
            await _context.SaveChangesAsync();

            transaction.Commit();
        }
示例#15
0
        /// <inheritdoc />
        public override void SetValue(object entity, object newValue, IResourceFactory resourceFactory)
        {
            base.SetValue(entity, newValue, resourceFactory);

            if (newValue == null)
            {
                ThroughProperty.SetValue(entity, null);
            }
            else
            {
                List <object> joinEntities = new List <object>();
                foreach (IIdentifiable resource in (IEnumerable)newValue)
                {
                    object joinEntity = resourceFactory.CreateInstance(ThroughType);
                    LeftProperty.SetValue(joinEntity, entity);
                    RightProperty.SetValue(joinEntity, resource);
                    joinEntities.Add(joinEntity);
                }

                var typedCollection = joinEntities.CopyToTypedCollection(ThroughProperty.PropertyType);
                ThroughProperty.SetValue(entity, typedCollection);
            }
        }