/// <inheritdoc /> // triggered by GET /articles/1/relationships/{relationshipName} public virtual async Task <TResource> GetRelationshipAsync(TId id, string relationshipName) { _traceWriter.LogMethodStart(new { id, relationshipName }); if (relationshipName == null) { throw new ArgumentNullException(nameof(relationshipName)); } AssertRelationshipExists(relationshipName); _hookExecutor?.BeforeRead <TResource>(ResourcePipeline.GetRelationship, id.ToString()); var secondaryLayer = _queryLayerComposer.Compose(_request.SecondaryResource); secondaryLayer.Projection = _queryLayerComposer.GetSecondaryProjectionForRelationshipEndpoint(_request.SecondaryResource); secondaryLayer.Include = null; var primaryLayer = _queryLayerComposer.WrapLayerForSecondaryEndpoint(secondaryLayer, _request.PrimaryResource, id, _request.Relationship); var primaryResources = await _repository.GetAsync(primaryLayer); var primaryResource = primaryResources.SingleOrDefault(); AssertPrimaryResourceExists(primaryResource); if (_hookExecutor != null) { _hookExecutor.AfterRead(AsList(primaryResource), ResourcePipeline.GetRelationship); primaryResource = _hookExecutor.OnReturn(AsList(primaryResource), ResourcePipeline.GetRelationship).Single(); } return(primaryResource); }
/// <inheritdoc /> public virtual async Task <object> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { id, relationshipName }); AssertHasRelationship(_request.Relationship, relationshipName); _hookExecutor.BeforeReadSingle <TResource, TId>(id, ResourcePipeline.GetRelationship); QueryLayer secondaryLayer = _queryLayerComposer.ComposeFromConstraints(_request.SecondaryResource); QueryLayer primaryLayer = _queryLayerComposer.WrapLayerForSecondaryEndpoint(secondaryLayer, _request.PrimaryResource, id, _request.Relationship); IReadOnlyCollection <TResource> primaryResources = await _repositoryAccessor.GetAsync <TResource>(primaryLayer, cancellationToken); TResource primaryResource = primaryResources.SingleOrDefault(); AssertPrimaryResourceExists(primaryResource); _hookExecutor.AfterReadSingle(primaryResource, ResourcePipeline.GetRelationship); object secondaryResourceOrResources = _request.Relationship.GetValue(primaryResource); if (secondaryResourceOrResources is ICollection secondaryResources && secondaryLayer.Pagination?.PageSize?.Value == secondaryResources.Count) { _paginationContext.IsPageFull = true; } return(_hookExecutor.OnReturnRelationship(secondaryResourceOrResources)); }
/// <inheritdoc /> public virtual async Task <object> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken) { _traceWriter.LogMethodStart(new { id, relationshipName }); AssertHasRelationship(_request.Relationship, relationshipName); _hookExecutor.BeforeReadSingle <TResource, TId>(id, ResourcePipeline.GetRelationship); QueryLayer secondaryLayer = _queryLayerComposer.ComposeFromConstraints(_request.SecondaryResource); QueryLayer primaryLayer = _queryLayerComposer.WrapLayerForSecondaryEndpoint(secondaryLayer, _request.PrimaryResource, id, _request.Relationship); if (_request.IsCollection && _options.IncludeTotalResourceCount) { // TODO: Consider support for pagination links on secondary resource collection. This requires to call Count() on the inverse relationship (which may not exist). // For /blogs/1/articles we need to execute Count(Articles.Where(article => article.Blog.Id == 1 && article.Blog.existingFilter))) to determine TotalResourceCount. // This also means we need to invoke ResourceRepository<Article>.CountAsync() from ResourceService<Blog>. // And we should call BlogResourceDefinition.OnApplyFilter to filter out soft-deleted blogs and translate from equals('IsDeleted','false') to equals('Blog.IsDeleted','false') } IReadOnlyCollection <TResource> primaryResources = await _repositoryAccessor.GetAsync <TResource>(primaryLayer, cancellationToken); TResource primaryResource = primaryResources.SingleOrDefault(); AssertPrimaryResourceExists(primaryResource); _hookExecutor.AfterReadSingle(primaryResource, ResourcePipeline.GetRelationship); object secondaryResourceOrResources = _request.Relationship.GetValue(primaryResource); if (secondaryResourceOrResources is ICollection secondaryResources && secondaryLayer.Pagination?.PageSize?.Value == secondaryResources.Count) { _paginationContext.IsPageFull = true; } return(_hookExecutor.OnReturnRelationship(secondaryResourceOrResources)); }