Example #1
0
        /// <summary>
        /// Parses all relationships from <paramref name="type" /> to other models in the resource resourceGraphs by constructing RelationshipProxies .
        /// </summary>
        /// <param name="type">
        /// The type to parse
        /// </param>
        private void RegisterRelationshipProxies(RightType type)
        {
            foreach (RelationshipAttribute attr in _resourceGraph.GetRelationships(type))
            {
                if (!attr.CanInclude)
                {
                    continue;
                }

                if (!_relationshipProxies.TryGetValue(attr, out _))
                {
                    RightType rightType         = GetRightTypeFromRelationship(attr);
                    bool      isContextRelation = false;
                    ISet <RelationshipAttribute> relationshipsToUpdate = _targetedFields.Relationships;

                    if (relationshipsToUpdate != null)
                    {
                        isContextRelation = relationshipsToUpdate.Contains(attr);
                    }

                    var proxy = new RelationshipProxy(attr, rightType, isContextRelation);
                    _relationshipProxies[attr] = proxy;
                }
            }
        }
Example #2
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);
        }
        /// <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 />
        /// <remarks>
        /// Note: this method does NOT check if a relationship is included to determine
        /// if it should be serialized. This is because completely hiding a relationship
        /// is not the same as not including. In the case of the latter,
        /// we may still want to add the relationship to expose the navigation link to the client.
        /// </remarks>
        public IReadOnlyCollection <RelationshipAttribute> GetRelationships(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            return(_resourceGraph.GetRelationships(type));
        }
Example #5
0
        /// <inheritdoc />
        /// <remarks>
        /// Note: this method does NOT check if a relationship is included to determine
        /// if it should be serialized. This is because completely hiding a relationship
        /// is not the same as not including. In the case of the latter,
        /// we may still want to add the relationship to expose the navigation link to the client.
        /// </remarks>
        public IReadOnlyCollection <RelationshipAttribute> GetRelationships(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            return(_request.Kind == EndpointKind.Relationship
                ? Array.Empty <RelationshipAttribute>()
                : _resourceGraph.GetRelationships(type));
        }
Example #6
0
        /// <inheritdoc/>
        /// <remarks>
        /// Note: this method does NOT check if a relationship is included to determine
        /// if it should be serialized. This is because completely hiding a relationship
        /// is not the same as not including. In the case of the latter,
        /// we may still want to add the relationship to expose the navigation link to the client.
        /// </remarks>
        public List <RelationshipAttribute> GetAllowedRelationships(Type type)
        {
            var resourceDefinition = _provider.Get(type);

            if (resourceDefinition != null)
            {
                // The set of allowed attributes to be exposed was defined on the resource definition
                return(resourceDefinition.GetAllowedRelationships());
            }

            // The set of allowed attributes to be exposed was NOT defined on the resource definition: return all
            return(_resourceGraph.GetRelationships(type));
        }
        /// <summary>
        /// By default, the client serializer does not include any relationships
        /// for entities in the primary data unless explicitly included using
        /// <see cref="RelationshipsToSerialize"/>.
        /// </summary>
        private List <RelationshipAttribute> GetRelationshipsToSerialize(IIdentifiable entity)
        {
            var currentResourceType = entity.GetType();

            // only allow relationship attributes to be serialized if they were set using
            // <see cref="RelationshipsToInclude{T}(Expression{Func{T, dynamic}})"/>
            // and the current <paramref name="entity"/> is a main entry in the primary data.
            if (RelationshipsToSerialize == null)
            {
                return(_resourceGraph.GetRelationships(currentResourceType));
            }

            return(RelationshipsToSerialize.ToList());
        }
        /// <summary>
        /// By default, the client serializer does not include any relationships
        /// for resources in the primary data unless explicitly included using
        /// <see cref="RelationshipsToSerialize"/>.
        /// </summary>
        private IReadOnlyCollection <RelationshipAttribute> GetRelationshipsToSerialize(IIdentifiable resource)
        {
            var currentResourceType = resource.GetType();

            // only allow relationship attributes to be serialized if they were set using
            // <see cref="RelationshipsToInclude{T}(Expression{Func{T, dynamic}})"/>
            // and the current resource is a primary entry.
            if (RelationshipsToSerialize == null)
            {
                return(_resourceGraph.GetRelationships(currentResourceType));
            }

            return(RelationshipsToSerialize);
        }
        private bool IsHasOneRelationship(string internalRelationshipName, Type type)
        {
            var relationshipAttr = _resourceGraph.GetRelationships(type).FirstOrDefault(r => r.InternalRelationshipName == internalRelationshipName);

            if (relationshipAttr != null)
            {
                if (relationshipAttr is HasOneAttribute)
                {
                    return(true);
                }

                return(false);
            }
            // relationshipAttr is null when we don't put a [RelationshipAttribute] on the inverse navigation property.
            // In this case we use relfection to figure out what kind of relationship is pointing back.
            return(!type.GetProperty(internalRelationshipName).PropertyType.Inherits(typeof(IEnumerable)));
        }
Example #10
0
        private JsonApiResourceService <TodoItem> GetService()
        {
            var options                    = new JsonApiOptions();
            var changeTracker              = new ResourceChangeTracker <TodoItem>(options, _resourceGraph, new TargetedFields());
            var serviceProvider            = new ServiceContainer();
            var resourceFactory            = new ResourceFactory(serviceProvider);
            var resourceDefinitionProvider = new ResourceDefinitionProvider(_resourceGraph, new TestScopedServiceProvider(serviceProvider));
            var paginationContext          = new PaginationContext();
            var composer                   = new QueryLayerComposer(new List <IQueryConstraintProvider>(), _resourceGraph, resourceDefinitionProvider, options, paginationContext);
            var currentRequest             = new CurrentRequest
            {
                PrimaryResource   = _resourceGraph.GetResourceContext <TodoItem>(),
                SecondaryResource = _resourceGraph.GetResourceContext <TodoItemCollection>(),
                Relationship      = _resourceGraph.GetRelationships(typeof(TodoItem))
                                    .Single(x => x.PublicName == "collection")
            };

            return(new JsonApiResourceService <TodoItem>(_repositoryMock.Object, composer, paginationContext, options,
                                                         NullLoggerFactory.Instance, currentRequest, changeTracker, resourceFactory, null));
        }
 /// <inheritdoc/>
 /// <remarks>
 /// Note: this method does NOT check if a relationship is included to determine
 /// if it should be serialized. This is because completely hiding a relationship
 /// is not the same as not including. In the case of the latter,
 /// we may still want to add the relationship to expose the navigation link to the client.
 /// </remarks>
 public IReadOnlyCollection <RelationshipAttribute> GetRelationships(Type type)
 {
     return(_resourceGraph.GetRelationships(type));
 }