/// <summary> /// Applies the provided flattened resource reference to the build result using the suplied builder context. /// </summary> /// <param name="member">The flattened ReferencedResource or EmbeddedObject to be applied to the build result.</param> /// <param name="builderContext">The builder context.</param> public void ApplyFlattenedMember(ResourceMemberBase member, HqlBuilderContext builderContext) { _next.ApplyFlattenedMember(member, builderContext); }
private CompositeDefinitionProcessorContext CreateChildProcessorContext(TBuildResult parentResult, CompositeDefinitionProcessorContext processorContext, TBuilderContext parentingBuilderContext, XElement childElement, ResourceClassBase currentResourceClass, IResourceModel resourceModel, int childIndex) { ResourceClassBase childModel; AssociationView association; ResourceMemberBase resourceMember; string childMemberName = childElement.AttributeValue(CompositeDefinitionHelper.Name); string childMemberDisplayName = childElement.AttributeValue(CompositeDefinitionHelper.DisplayName); string currentElementName = processorContext.CurrentElement.AttributeValue(CompositeDefinitionHelper.Name); string resourceMemberName = string.Empty; string childEntityMemberName = string.Empty; switch (childElement.Name.LocalName) { case CompositeDefinitionHelper.Collection: if (!currentResourceClass.CollectionByName.TryGetValue(childMemberName, out Collection collection)) { ApplyValidationMessage("collection", childMemberName, currentElementName); return(null); } _logger.Debug($"Current element '{currentElementName}' is a collection named '{childMemberName}'."); childModel = collection.ItemType; childEntityMemberName = childMemberName; association = collection.Association; resourceMember = collection; resourceMemberName = collection.PropertyName; break; case CompositeDefinitionHelper.LinkedCollection: var resource = currentResourceClass as Resource; if (resource == null) { _logger.Debug($"Current resource class '{currentResourceClass.Name} is not an aggregate root."); return(null); } if (!resource.LinkedResourceCollectionByName.TryGetValue( childMemberName, out LinkedCollection linkedCollection)) { ApplyValidationMessage("linked collection", childMemberName, currentElementName); return(null); } _logger.Debug( $"Current element '{currentElementName} is a linked collection named '{childMemberName}' for resource '{currentResourceClass.Name}'."); childModel = linkedCollection.Resource; childEntityMemberName = childMemberName; association = linkedCollection.Association; resourceMember = linkedCollection; resourceMemberName = linkedCollection.PropertyName; break; case CompositeDefinitionHelper.EmbeddedObject: if (!currentResourceClass.EmbeddedObjectByName.TryGetValue( childMemberName, out EmbeddedObject embeddedObject)) { ApplyValidationMessage("embedded object", childMemberName, currentElementName); return(null); } _logger.Debug($"Current element '{currentElementName}' is an embedded object named '{childMemberName}'."); childModel = embeddedObject.ObjectType; childEntityMemberName = embeddedObject.Association.Name; association = embeddedObject.Association; resourceMember = embeddedObject; resourceMemberName = embeddedObject.PropertyName; if (CompositeDefinitionHelper.ShouldFlatten(childElement)) { _logger.Debug($"Flattening embedded object {childModel.Name}"); _compositeBuilder.ApplyFlattenedMember(embeddedObject, parentingBuilderContext); var childBuilderContextForObject = _compositeBuilder.CreateFlattenedReferenceChildContext(parentingBuilderContext); var childProcessorContextForObject = new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, resourceModel, childElement, childModel, association, childEntityMemberName, resourceMemberName, childIndex, resourceMember); ProcessChildren(parentResult, childProcessorContextForObject, childBuilderContextForObject); return(null); } break; case CompositeDefinitionHelper.ReferencedResource: ResourceMemberBase resourceMemberToUseForFlattening; if (!currentResourceClass.ReferenceByName.TryGetValue(childMemberName, out Reference reference)) { // Look for a "descriptor" property if (currentResourceClass.PropertyByName.TryGetValue( childMemberName, out ResourceProperty descriptorProperty)) { resourceMemberToUseForFlattening = descriptorProperty; childModel = descriptorProperty.DescriptorResource; childEntityMemberName = childMemberName; association = descriptorProperty.EntityProperty.IncomingAssociations.FirstOrDefault(); resourceMember = descriptorProperty; resourceMemberName = childMemberName; } else { ApplyValidationMessage("referenced resource", childMemberName, currentElementName); return(null); } } else { _logger.Debug( $"Current element '{currentElementName}' is a referenced resourced named '{childMemberName}'."); resourceMemberToUseForFlattening = reference; childModel = reference.ReferencedResource; childEntityMemberName = reference.Association.Name; association = reference.Association; resourceMember = reference; resourceMemberName = reference.PropertyName; } // If reference is flattened, process recursively without adding another query at this level. if (CompositeDefinitionHelper.ShouldFlatten(childElement)) { _logger.Debug($"Flattening referenced resource {childModel.Name}"); _compositeBuilder.ApplyFlattenedMember(resourceMemberToUseForFlattening, parentingBuilderContext); var childBuilderContextForReference = _compositeBuilder.CreateFlattenedReferenceChildContext(parentingBuilderContext); var childProcessorContextForReference = new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, resourceModel, childElement, childModel, association, childEntityMemberName, resourceMemberName, childIndex, resourceMember); if (childModel.Entity.IsAggregateRoot) { // Provide opportunity to perform processing related to navigating into another resource (i.e. authorization) if (!_compositeBuilder.TryIncludeResource( childProcessorContextForReference, childBuilderContextForReference)) { return(null); } } ProcessChildren(parentResult, childProcessorContextForReference, childBuilderContextForReference); return(null); } break; default: throw new NotSupportedException($"Element '{childElement.Name.LocalName}' is not supported."); } return(new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, resourceModel, childElement, childModel, association, childEntityMemberName, childMemberDisplayName ?? resourceMemberName, childIndex, resourceMember)); }