예제 #1
0
 /// <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));
        }