/// <inheritdoc />
        public virtual async Task DeleteAsync(TId id, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                id
            });

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
            TResource resource = collector.CreateForId <TResource, TId>(id);

            foreach (RelationshipAttribute relationship in _resourceGraph.GetRelationships <TResource>())
            {
                // Loads the data of the relationship, if in EF Core it is configured in such a way that loading the related
                // entities into memory is required for successfully executing the selected deletion behavior.
                if (RequiresLoadOfRelationshipForDeletion(relationship))
                {
                    NavigationEntry navigation = GetNavigationEntry(resource, relationship);
                    await navigation.LoadAsync(cancellationToken);
                }
            }

            _dbContext.Remove(resource);

            await SaveChangesAsync(cancellationToken);
        }
        /// <inheritdoc />
        public virtual async Task RemoveFromToManyRelationshipAsync(TResource primaryResource, ISet <IIdentifiable> secondaryResourceIds,
                                                                    CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                primaryResource,
                secondaryResourceIds
            });

            ArgumentGuard.NotNull(secondaryResourceIds, nameof(secondaryResourceIds));

            var relationship = (HasManyAttribute)_targetedFields.Relationships.Single();

            object rightValue = relationship.GetValue(primaryResource);

            HashSet <IIdentifiable> rightResourceIds = _collectionConverter.ExtractResources(rightValue).ToHashSet(IdentifiableComparer.Instance);

            rightResourceIds.ExceptWith(secondaryResourceIds);

            AssertIsNotClearingRequiredRelationship(relationship, primaryResource, rightResourceIds);

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
            await UpdateRelationshipAsync(relationship, primaryResource, rightResourceIds, collector, cancellationToken);

            await SaveChangesAsync(cancellationToken);
        }
        /// <inheritdoc />
        public virtual async Task CreateAsync(TResource resourceFromRequest, TResource resourceForDatabase, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new { resourceFromRequest, resourceForDatabase });

            ArgumentGuard.NotNull(resourceFromRequest, nameof(resourceFromRequest));
            ArgumentGuard.NotNull(resourceForDatabase, nameof(resourceForDatabase));

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);

            foreach (var relationship in _targetedFields.Relationships)
            {
                var rightResources = relationship.GetValue(resourceFromRequest);
                await UpdateRelationshipAsync(relationship, resourceForDatabase, rightResources, collector, cancellationToken);
            }

            foreach (var attribute in _targetedFields.Attributes)
            {
                attribute.SetValue(resourceForDatabase, attribute.GetValue(resourceFromRequest));
            }

            var dbSet = _dbContext.Set <TResource>();
            await dbSet.AddAsync(resourceForDatabase, cancellationToken);

            await SaveChangesAsync(cancellationToken);
        }
        /// <inheritdoc />
        public virtual async Task UpdateAsync(TResource resourceFromRequest, TResource resourceFromDatabase, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                resourceFromRequest,
                resourceFromDatabase
            });

            ArgumentGuard.NotNull(resourceFromRequest, nameof(resourceFromRequest));
            ArgumentGuard.NotNull(resourceFromDatabase, nameof(resourceFromDatabase));

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);

            foreach (RelationshipAttribute relationship in _targetedFields.Relationships)
            {
                object rightResources = relationship.GetValue(resourceFromRequest);

                AssertIsNotClearingRequiredRelationship(relationship, resourceFromDatabase, rightResources);

                await UpdateRelationshipAsync(relationship, resourceFromDatabase, rightResources, collector, cancellationToken);
            }

            foreach (AttrAttribute attribute in _targetedFields.Attributes)
            {
                attribute.SetValue(resourceFromDatabase, attribute.GetValue(resourceFromRequest));
            }

            await SaveChangesAsync(cancellationToken);
        }
예제 #5
0
        /// <inheritdoc />
        public virtual async Task DeleteAsync(TId id, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                id
            });

            // This enables OnWritingAsync() to fetch the resource, which adds it to the change tracker.
            // If so, we'll reuse the tracked resource instead of a placeholder resource.
            var emptyResource = _resourceFactory.CreateInstance <TResource>();

            emptyResource.Id = id;

            await _resourceDefinitionAccessor.OnWritingAsync(emptyResource, OperationKind.DeleteResource, cancellationToken);

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
            TResource resource = collector.CreateForId <TResource, TId>(id);

            foreach (RelationshipAttribute relationship in _resourceGraph.GetRelationships <TResource>())
            {
                // Loads the data of the relationship, if in EF Core it is configured in such a way that loading the related
                // entities into memory is required for successfully executing the selected deletion behavior.
                if (RequiresLoadOfRelationshipForDeletion(relationship))
                {
                    NavigationEntry navigation = GetNavigationEntry(resource, relationship);
                    await navigation.LoadAsync(cancellationToken);
                }
            }

            _dbContext.Remove(resource);

            await SaveChangesAsync(cancellationToken);

            await _resourceDefinitionAccessor.OnWriteSucceededAsync(resource, OperationKind.DeleteResource, cancellationToken);
        }
예제 #6
0
        /// <inheritdoc />
        public virtual async Task AddToToManyRelationshipAsync(TId primaryId, ISet <IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                primaryId,
                secondaryResourceIds
            });

            ArgumentGuard.NotNull(secondaryResourceIds, nameof(secondaryResourceIds));

            var relationship = (HasManyAttribute)_targetedFields.Relationships.Single();

            await _resourceDefinitionAccessor.OnAddToRelationshipAsync <TResource, TId>(primaryId, relationship, secondaryResourceIds, cancellationToken);

            if (secondaryResourceIds.Any())
            {
                using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
                TResource primaryResource = collector.CreateForId <TResource, TId>(primaryId);

                await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIds, collector, cancellationToken);

                await _resourceDefinitionAccessor.OnWritingAsync(primaryResource, OperationKind.AddToRelationship, cancellationToken);

                await SaveChangesAsync(cancellationToken);

                await _resourceDefinitionAccessor.OnWriteSucceededAsync(primaryResource, OperationKind.AddToRelationship, cancellationToken);
            }
        }
        /// <inheritdoc />
        public virtual async Task SetRelationshipAsync(TResource primaryResource, object secondaryResourceIds, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new { primaryResource, secondaryResourceIds });

            var relationship = _targetedFields.Relationships.Single();

            AssertIsNotClearingRequiredRelationship(relationship, primaryResource, secondaryResourceIds);

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
            await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIds, collector, cancellationToken);

            await SaveChangesAsync(cancellationToken);
        }
        protected async Task UpdateRelationshipAsync(RelationshipAttribute relationship, TResource leftResource, object valueToAssign,
                                                     PlaceholderResourceCollector collector, CancellationToken cancellationToken)
        {
            object trackedValueToAssign = EnsureRelationshipValueToAssignIsTracked(valueToAssign, relationship.Property.PropertyType, collector);

            if (RequireLoadOfInverseRelationship(relationship, trackedValueToAssign))
            {
                EntityEntry entityEntry         = _dbContext.Entry(trackedValueToAssign);
                string      inversePropertyName = relationship.InverseNavigationProperty.Name;

                await entityEntry.Reference(inversePropertyName).LoadAsync(cancellationToken);
            }

            relationship.SetValue(leftResource, trackedValueToAssign);
        }
        private object EnsureRelationshipValueToAssignIsTracked(object rightValue, Type relationshipPropertyType,
                                                                PlaceholderResourceCollector collector)
        {
            if (rightValue == null)
            {
                return(null);
            }

            var rightResources        = TypeHelper.ExtractResources(rightValue);
            var rightResourcesTracked = rightResources.Select(collector.CaptureExisting).ToArray();

            return(rightValue is IEnumerable
                ? (object)TypeHelper.CopyToTypedCollection(rightResourcesTracked, relationshipPropertyType)
                : rightResourcesTracked.Single());
        }
예제 #10
0
        /// <inheritdoc />
        public virtual async Task AddToToManyRelationshipAsync(TId primaryId, ISet <IIdentifiable> secondaryResourceIds, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new { primaryId, secondaryResourceIds });
            if (secondaryResourceIds == null)
            {
                throw new ArgumentNullException(nameof(secondaryResourceIds));
            }

            var relationship = _targetedFields.Relationships.Single();

            if (secondaryResourceIds.Any())
            {
                using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
                var primaryResource = collector.CreateForId <TResource, TId>(primaryId);

                await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIds, collector, cancellationToken);

                await SaveChangesAsync(cancellationToken);
            }
        }
예제 #11
0
        /// <inheritdoc />
        public virtual async Task CreateAsync(TResource resource, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new { resource });
            if (resource == null)
            {
                throw new ArgumentNullException(nameof(resource));
            }

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);

            foreach (var relationship in _targetedFields.Relationships)
            {
                var rightValue = relationship.GetValue(resource);
                await UpdateRelationshipAsync(relationship, resource, rightValue, collector, cancellationToken);
            }

            var dbSet = _dbContext.Set <TResource>();

            dbSet.Add(resource);

            await SaveChangesAsync(cancellationToken);
        }
예제 #12
0
        /// <inheritdoc />
        public virtual async Task CreateAsync(TResource resourceFromRequest, TResource resourceForDatabase, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                resourceFromRequest,
                resourceForDatabase
            });

            ArgumentGuard.NotNull(resourceFromRequest, nameof(resourceFromRequest));
            ArgumentGuard.NotNull(resourceForDatabase, nameof(resourceForDatabase));

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);

            foreach (RelationshipAttribute relationship in _targetedFields.Relationships)
            {
                object rightResources = relationship.GetValue(resourceFromRequest);

                object rightResourcesEdited = await VisitSetRelationshipAsync(resourceForDatabase, relationship, rightResources, OperationKind.CreateResource,
                                                                              cancellationToken);

                await UpdateRelationshipAsync(relationship, resourceForDatabase, rightResourcesEdited, collector, cancellationToken);
            }

            foreach (AttrAttribute attribute in _targetedFields.Attributes)
            {
                attribute.SetValue(resourceForDatabase, attribute.GetValue(resourceFromRequest));
            }

            await _resourceDefinitionAccessor.OnWritingAsync(resourceForDatabase, OperationKind.CreateResource, cancellationToken);

            DbSet <TResource> dbSet = _dbContext.Set <TResource>();
            await dbSet.AddAsync(resourceForDatabase, cancellationToken);

            await SaveChangesAsync(cancellationToken);

            await _resourceDefinitionAccessor.OnWriteSucceededAsync(resourceForDatabase, OperationKind.CreateResource, cancellationToken);
        }
예제 #13
0
        /// <inheritdoc />
        public virtual async Task SetRelationshipAsync(TResource primaryResource, object secondaryResourceIds, CancellationToken cancellationToken)
        {
            _traceWriter.LogMethodStart(new
            {
                primaryResource,
                secondaryResourceIds
            });

            RelationshipAttribute relationship = _targetedFields.Relationships.Single();

            object secondaryResourceIdsEdited =
                await VisitSetRelationshipAsync(primaryResource, relationship, secondaryResourceIds, OperationKind.SetRelationship, cancellationToken);

            AssertIsNotClearingRequiredRelationship(relationship, primaryResource, secondaryResourceIdsEdited);

            using var collector = new PlaceholderResourceCollector(_resourceFactory, _dbContext);
            await UpdateRelationshipAsync(relationship, primaryResource, secondaryResourceIdsEdited, collector, cancellationToken);

            await _resourceDefinitionAccessor.OnWritingAsync(primaryResource, OperationKind.SetRelationship, cancellationToken);

            await SaveChangesAsync(cancellationToken);

            await _resourceDefinitionAccessor.OnWriteSucceededAsync(primaryResource, OperationKind.SetRelationship, cancellationToken);
        }
예제 #14
0
        private object EnsureRelationshipValueToAssignIsTracked(object rightValue, Type relationshipPropertyType, PlaceholderResourceCollector collector)
        {
            if (rightValue == null)
            {
                return null;
            }

            ICollection<IIdentifiable> rightResources = _collectionConverter.ExtractResources(rightValue);
            IIdentifiable[] rightResourcesTracked = rightResources.Select(collector.CaptureExisting).ToArray();

            return rightValue is IEnumerable
                ? (object)_collectionConverter.CopyToTypedCollection(rightResourcesTracked, relationshipPropertyType)
                : rightResourcesTracked.Single();
        }