Пример #1
0
 /// <summary>
 /// Builds a new context from the curent builder context for use in processing a flattened reference.
 /// </summary>
 /// <param name="builderContext">The builder context.</param>
 /// <returns>The new builder context for use in processing a flattened reference.</returns>
 public HqlBuilderContext CreateFlattenedMemberContext(HqlBuilderContext builderContext)
 {
     return(_next.CreateFlattenedMemberContext(builderContext));
 }
        private void ProcessFlattenedMemberProperties(
            CompositeDefinitionProcessorContext processorContext,
            TBuilderContext builderContext)
        {
            string currentContainingElementName = processorContext.CurrentElement.AttributeValue(CompositeDefinitionHelper.Name);

            var flattenedMemberElements = processorContext.CurrentElement
                                          .Elements(CompositeDefinitionHelper.ReferencedResource)
                                          .Where(CompositeDefinitionHelper.ShouldFlatten)
                                          .ToList();

            flattenedMemberElements.AddRange(
                processorContext.CurrentElement
                .Elements(CompositeDefinitionHelper.EmbeddedObject)
                .Where(CompositeDefinitionHelper.ShouldFlatten));

            foreach (var flattenedMemberElt in flattenedMemberElements)
            {
                string flattenedMemberName = flattenedMemberElt.AttributeValue(CompositeDefinitionHelper.Name);

                ResourceMemberBase resourceMemberToUse = null;
                Resource           flattenedResource   = null;

                bool memberIsReference      = flattenedMemberElt.Name.LocalName == CompositeDefinitionHelper.ReferencedResource;
                bool memberIsEmbeddedObject = flattenedMemberElt.Name.LocalName == CompositeDefinitionHelper.EmbeddedObject;

                if (memberIsReference)
                {
                    if (!processorContext.CurrentResourceClass.ReferenceByName.TryGetValue(
                            flattenedMemberName, out Reference resourceToUseAsReference))
                    {
                        // Look for a "descriptor" property
                        if (processorContext.CurrentResourceClass.PropertyByName.TryGetValue(
                                flattenedMemberName,
                                out ResourceProperty descriptorProperty))
                        {
                            resourceMemberToUse = descriptorProperty;

                            flattenedResource =
                                processorContext.CurrentResourceClass.ResourceModel.GetResourceByFullName(
                                    descriptorProperty.DescriptorResource.Entity.FullName);
                        }
                        else
                        {
                            ApplyValidationMessage("resource reference", flattenedMemberName, currentContainingElementName);
                            continue;
                        }
                    }
                    else
                    {
                        resourceMemberToUse = resourceToUseAsReference;

                        flattenedResource =
                            processorContext.CurrentResourceClass.ResourceModel.GetResourceByFullName(
                                resourceToUseAsReference.ReferencedResource.Entity.FullName);
                    }
                }
                else if (memberIsEmbeddedObject)
                {
                    if (!processorContext.CurrentResourceClass.EmbeddedObjectByName.TryGetValue(
                            flattenedMemberName, out EmbeddedObject resourceAsEmbeddedObject))
                    {
                        ApplyValidationMessage("embedded object", flattenedMemberName, currentContainingElementName);
                        continue;
                    }

                    resourceMemberToUse = resourceAsEmbeddedObject;

                    flattenedResource =
                        processorContext.CurrentResourceClass.ResourceModel.GetResourceByFullName(
                            resourceAsEmbeddedObject.Parent.Entity.FullName);
                }
                else
                {
                    // Defensive programming, but also throw a helpful message in the event it does ever happen
                    throw new NotSupportedException(
                              $"Flattened elements of type '{flattenedMemberElt.Name.LocalName}' are not yet supported.");
                }

                var flattenedBuilderContext = _compositeBuilder.CreateFlattenedMemberContext(builderContext);

                var flattenedProcessingContext = new CompositeDefinitionProcessorContext(
                    processorContext.CompositeDefinitionElement,
                    processorContext.ResourceModel,
                    flattenedMemberElt,
                    flattenedResource,
                    null,
                    null,
                    null,
                    0,
                    resourceMemberToUse);

                var shouldContinueWithValidation = resourceMemberToUse == null && _performValidation;

                if (flattenedResource.Entity.IsAggregateRoot)
                {
                    // Provide opportunity to perform processing related to navigating into another resource (i.e. authorization)
                    if (!_compositeBuilder.TryIncludeResource(flattenedProcessingContext, flattenedBuilderContext))
                    {
                        continue;
                    }
                }

                if (shouldContinueWithValidation)
                {
                    continue;
                }

                _compositeBuilder.ApplyFlattenedMember(resourceMemberToUse, flattenedBuilderContext);

                // TODO: Consider refining what is passed into Resource model classes rather than XElements
                var propertyElements = flattenedMemberElt
                                       .Elements(CompositeDefinitionHelper.Property)
                                       .ToList();

                List <CompositePropertyProjection> flattenedPropertyProjections = new List <CompositePropertyProjection>();

                if (memberIsReference)
                {
                    flattenedPropertyProjections = GetPropertyProjections(
                        flattenedProcessingContext,
                        propertyElements);
                }
                else if (memberIsEmbeddedObject)
                {
                    flattenedPropertyProjections = GetPropertyProjectionsForNonAggregateRoot(
                        processorContext,
                        (EmbeddedObject)resourceMemberToUse,
                        propertyElements,
                        currentContainingElementName);
                }

                _compositeBuilder.ProjectProperties(
                    flattenedPropertyProjections, flattenedBuilderContext, flattenedProcessingContext);

                // Recursively process flattened resource properties
                ProcessFlattenedMemberProperties(
                    flattenedProcessingContext,
                    flattenedBuilderContext);
            }
        }