/// <summary>
        /// Determines if the cache already contains a value for the specified EPM mapping.
        /// </summary>
        /// <param name="epmInfo">The EPM info for the EPM mapping to look for.</param>
        /// <returns>true if the cache already contains a value for this mapping, false otherwise.</returns>
        internal bool Contains(EntityPropertyMappingInfo epmInfo)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(epmInfo != null, "epmInfo != null");

            return this.customEpmValues.Any(epmValue => object.ReferenceEquals(epmValue.Key, epmInfo));
        }
Example #2
0
        /// <summary>Compares the defining type of this info and other EpmInfo object.</summary>
        /// <param name="other">The other EpmInfo object to compare to.</param>
        /// <returns>true if the defining types are the same</returns>
        internal bool DefiningTypesAreEqual(EntityPropertyMappingInfo other)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(other != null, "other != null");

            return(this.DefiningType.IsEquivalentTo(other.DefiningType));
        }
Example #3
0
 private static string GetPropertyNameFromEpmInfo(EntityPropertyMappingInfo epmInfo)
 {
     if (epmInfo.Attribute.TargetSyndicationItem == SyndicationItemProperty.CustomProperty)
     {
         return(epmInfo.Attribute.TargetPath);
     }
     return(epmInfo.Attribute.TargetSyndicationItem.ToString());
 }
Example #4
0
        internal void Add(EntityPropertyMappingInfo epmInfo)
        {
            List <EpmSourcePathSegment> list     = new List <EpmSourcePathSegment>();
            EpmSourcePathSegment        root     = this.Root;
            EpmSourcePathSegment        segment2 = null;
            IEdmType actualPropertyType          = epmInfo.ActualPropertyType;

            string[] strArray = epmInfo.Attribute.SourcePath.Split(new char[] { '/' });
            int      length   = strArray.Length;

            for (int i = 0; i < length; i++)
            {
                string propertyName = strArray[i];
                if (propertyName.Length == 0)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }
                IEdmTypeReference propertyType = GetPropertyType(actualPropertyType, propertyName);
                IEdmType          type2        = (propertyType == null) ? null : propertyType.Definition;
                if ((type2 == null) && (i < (length - 1)))
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, actualPropertyType.ODataFullName()));
                }
                actualPropertyType = type2;
                segment2           = root.SubProperties.SingleOrDefault <EpmSourcePathSegment>(e => e.PropertyName == propertyName);
                if (segment2 != null)
                {
                    root = segment2;
                }
                else
                {
                    EpmSourcePathSegment item = new EpmSourcePathSegment(propertyName);
                    root.SubProperties.Add(item);
                    root = item;
                }
                list.Add(root);
            }
            if ((actualPropertyType != null) && !actualPropertyType.IsODataPrimitiveTypeKind())
            {
                throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(root.PropertyName));
            }
            if (segment2 != null)
            {
                if (segment2.EpmInfo.DefiningTypesAreEqual(epmInfo))
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }
                this.epmTargetTree.Remove(segment2.EpmInfo);
            }
            epmInfo.SetPropertyValuePath(list.ToArray());
            root.EpmInfo = epmInfo;
            this.epmTargetTree.Add(epmInfo);
        }
Example #5
0
        /// <summary>
        /// Removes a path in the tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/>.
        /// </summary>
        /// <param name="epmInfo">EnitityPropertyMappingInfo holding the target path</param>
        internal void Remove(EntityPropertyMappingInfo epmInfo)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(epmInfo != null, "epmInfo != null");

            string targetName   = epmInfo.Attribute.TargetPath;
            string namespaceUri = epmInfo.Attribute.TargetNamespaceUri;

            EpmTargetPathSegment        currentSegment    = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot;
            List <EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments;

            Debug.Assert(!string.IsNullOrEmpty(targetName), "Must have been validated during EntityPropertyMappingAttribute construction");
            string[] targetSegments = targetName.Split('/');
            for (int i = 0; i < targetSegments.Length; i++)
            {
                string targetSegment = targetSegments[i];

                Debug.Assert(targetSegment.Length > 0 && (targetSegment[0] != '@' || i == targetSegments.Length - 1), "Target segments should have been checked when adding the path to the tree");

                EpmTargetPathSegment foundSegment = activeSubSegments.FirstOrDefault(
                    segment => segment.SegmentName == targetSegment &&
                    (epmInfo.IsSyndicationMapping || segment.SegmentNamespaceUri == namespaceUri));
                if (foundSegment != null)
                {
                    currentSegment = foundSegment;
                }
                else
                {
                    return;
                }

                activeSubSegments = currentSegment.SubSegments;
            }

            // Recursively remove all the parent segments which will have no more children left
            // after removal of the current segment node
            if (currentSegment.EpmInfo != null)
            {
                // Since we are removing a property with KeepInContent false, we should decrement the count
                if (!currentSegment.EpmInfo.Attribute.KeepInContent)
                {
                    this.countOfNonContentV2Mappings--;
                }

                EpmTargetPathSegment parentSegment = null;
                do
                {
                    parentSegment = currentSegment.ParentSegment;
                    parentSegment.SubSegments.Remove(currentSegment);
                    currentSegment = parentSegment;
                }while (currentSegment.ParentSegment != null && !currentSegment.HasContent && currentSegment.SubSegments.Count == 0);
            }
        }
Example #6
0
 internal void Add(EntityPropertyMappingInfo epmInfo)
 {
     List<EpmSourcePathSegment> list = new List<EpmSourcePathSegment>();
     EpmSourcePathSegment root = this.Root;
     EpmSourcePathSegment segment2 = null;
     IEdmType actualPropertyType = epmInfo.ActualPropertyType;
     string[] strArray = epmInfo.Attribute.SourcePath.Split(new char[] { '/' });
     int length = strArray.Length;
     for (int i = 0; i < length; i++)
     {
         string propertyName = strArray[i];
         if (propertyName.Length == 0)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
         }
         IEdmTypeReference propertyType = GetPropertyType(actualPropertyType, propertyName);
         IEdmType type2 = (propertyType == null) ? null : propertyType.Definition;
         if ((type2 == null) && (i < (length - 1)))
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, actualPropertyType.ODataFullName()));
         }
         actualPropertyType = type2;
         segment2 = root.SubProperties.SingleOrDefault<EpmSourcePathSegment>(e => e.PropertyName == propertyName);
         if (segment2 != null)
         {
             root = segment2;
         }
         else
         {
             EpmSourcePathSegment item = new EpmSourcePathSegment(propertyName);
             root.SubProperties.Add(item);
             root = item;
         }
         list.Add(root);
     }
     if ((actualPropertyType != null) && !actualPropertyType.IsODataPrimitiveTypeKind())
     {
         throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(root.PropertyName));
     }
     if (segment2 != null)
     {
         if (segment2.EpmInfo.DefiningTypesAreEqual(epmInfo))
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
         }
         this.epmTargetTree.Remove(segment2.EpmInfo);
     }
     epmInfo.SetPropertyValuePath(list.ToArray());
     root.EpmInfo = epmInfo;
     this.epmTargetTree.Add(epmInfo);
 }
Example #7
0
        /// <summary>
        /// Given an <see cref="EntityPropertyMappingInfo"/> gives the correct target path for it
        /// </summary>
        /// <param name="epmInfo">Given <see cref="EntityPropertyMappingInfo"/></param>
        /// <returns>string with the correct value for the target path</returns>
        private static string GetPropertyNameFromEpmInfo(EntityPropertyMappingInfo epmInfo)
        {
            if (epmInfo.Attribute.TargetSyndicationItem == SyndicationItemProperty.CustomProperty)
            {
                return(epmInfo.Attribute.TargetPath);
            }

            // for EF provider we want to return a name that corresponds to attribute in the edmx file while for CLR provider
            // and the client we want to return a name that corresponds to the enum value used in EntityPropertyMapping attribute.
            return
                (#if ASTORIA_SERVER
                 epmInfo.IsEFProvider ? EpmTranslate.MapSyndicationPropertyToEpmTargetPath(epmInfo.Attribute.TargetSyndicationItem) :
#endif
                 epmInfo.Attribute.TargetSyndicationItem.ToString());
        }
Example #8
0
        internal void Remove(EntityPropertyMappingInfo epmInfo)
        {
            string targetPath   = epmInfo.Attribute.TargetPath;
            string namespaceUri = epmInfo.Attribute.TargetNamespaceUri;
            EpmTargetPathSegment        item        = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot;
            List <EpmTargetPathSegment> subSegments = item.SubSegments;

            string[] strArray = targetPath.Split(new char[] { '/' });
            for (int i = 0; i < strArray.Length; i++)
            {
                string targetSegment          = strArray[i];
                EpmTargetPathSegment segment2 = subSegments.FirstOrDefault <EpmTargetPathSegment>(delegate(EpmTargetPathSegment segment) {
                    if (!(segment.SegmentName == targetSegment))
                    {
                        return(false);
                    }
                    if (!epmInfo.IsSyndicationMapping)
                    {
                        return(segment.SegmentNamespaceUri == namespaceUri);
                    }
                    return(true);
                });
                if (segment2 != null)
                {
                    item = segment2;
                }
                else
                {
                    return;
                }
                subSegments = item.SubSegments;
            }
            if (item.EpmInfo != null)
            {
                if (!item.EpmInfo.Attribute.KeepInContent)
                {
                    this.countOfNonContentV2Mappings--;
                }
                EpmTargetPathSegment parentSegment = null;
                do
                {
                    parentSegment = item.ParentSegment;
                    parentSegment.SubSegments.Remove(item);
                    item = parentSegment;
                }while (((item.ParentSegment != null) && !item.HasContent) && (item.SubSegments.Count == 0));
            }
        }
Example #9
0
        /// <summary>
        /// Reads a property value starting on an entry.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="epmValueCache">The EPM value cache for the entry to read from.</param>
        /// <param name="entityType">The type of the entry.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        protected object ReadEntryPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            EntryPropertiesValueCache epmValueCache,
            IEdmEntityTypeReference entityType)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > 0, "The PropertyValuePath must not be empty for an entry property.");
            Debug.Assert(entityType != null, "entityType != null");

            // TODO - It might be possible to avoid the "value" type checks below if we do property value validation based on the type
            return this.ReadPropertyValue(
                epmInfo,
                epmValueCache.EntryProperties,
                0,
                entityType,
                epmValueCache);
        }
Example #10
0
        internal void Add(EntityPropertyMappingInfo epmInfo)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(epmInfo != null, "epmInfo != null");

            string targetPath      = epmInfo.Attribute.TargetPath;
            string namespaceUri    = epmInfo.Attribute.TargetNamespaceUri;
            string namespacePrefix = epmInfo.Attribute.TargetNamespacePrefix;

            EpmTargetPathSegment         currentSegment    = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot;
            IList <EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments;

            Debug.Assert(!string.IsNullOrEmpty(targetPath), "Must have been validated during EntityPropertyMappingAttribute construction");
            string[] targetSegments = targetPath.Split('/');

            EpmTargetPathSegment foundSegment = null;

            for (int i = 0; i < targetSegments.Length; i++)
            {
                string targetSegment = targetSegments[i];

                if (targetSegment.Length == 0)
                {
                    throw new ODataException(Strings.EpmTargetTree_InvalidTargetPath_EmptySegment(targetPath));
                }

                if (targetSegment[0] == '@' && i != targetSegments.Length - 1)
                {
                    throw new ODataException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment));
                }

                foundSegment = activeSubSegments.SingleOrDefault(
                    segment => segment.SegmentName == targetSegment &&
                    (epmInfo.IsSyndicationMapping || segment.SegmentNamespaceUri == namespaceUri));

                if (foundSegment != null)
                {
                    currentSegment = foundSegment;
                }
                else
                {
                    currentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, namespacePrefix, currentSegment);

                    if (targetSegment[0] == '@')
                    {
                        activeSubSegments.Insert(0, currentSegment);
                    }
                    else
                    {
                        activeSubSegments.Add(currentSegment);
                    }
                }

                activeSubSegments = currentSegment.SubSegments;
            }

            if (currentSegment.EpmInfo != null)
            {
                // Two EpmAttributes with same TargetName in the inheritance hierarchy
                throw new ODataException(Strings.EpmTargetTree_DuplicateEpmAttributesWithSameTargetName(currentSegment.EpmInfo.DefiningType.ODataFullName(), EpmTargetTree.GetPropertyNameFromEpmInfo(currentSegment.EpmInfo), currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath));
            }

            // Increment the number of properties for which KeepInContent is false
            if (!epmInfo.Attribute.KeepInContent)
            {
                this.countOfNonContentV2Mappings++;
            }

            currentSegment.EpmInfo = epmInfo;

            // Mixed content is dis-allowed.
            List <EntityPropertyMappingAttribute> conflictingAttributes = new List <EntityPropertyMappingAttribute>(2);

            if (EpmTargetTree.HasMixedContent(this.NonSyndicationRoot, conflictingAttributes))
            {
                Debug.Assert(conflictingAttributes.Count == 2, "Expected to find exactly two conflicting attributes.");
                throw new ODataException(Strings.EpmTargetTree_InvalidTargetPath_MixedContent(conflictingAttributes[0].TargetPath, conflictingAttributes[1].TargetPath));
            }
        }
Example #11
0
 protected void SetEpmValue(IList targetList, IEdmTypeReference targetTypeReference, EntityPropertyMappingInfo epmInfo, object propertyValue)
 {
     this.SetEpmValueForSegment(epmInfo, 0, targetTypeReference.AsStructuredOrNull(), (List<ODataProperty>) targetList, propertyValue);
 }
        /// <summary>
        /// Adds a value to cache.
        /// </summary>
        /// <param name="epmInfo">The EPM info for the mapping according to which the value was read.</param>
        /// <param name="value">The value to cache.</param>
        /// <remarks>
        /// The method will only store the first value for any given EPM info, since in custom EPM
        /// only the first occurrence of the element/attribute is used, the others are ignored.
        /// </remarks>
        internal void Add(EntityPropertyMappingInfo epmInfo, string value)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(!this.Contains(epmInfo), "We should not be trying to add more than one value for any given mapping.");

            this.customEpmValues.Add(new KeyValuePair<EntityPropertyMappingInfo, string>(epmInfo, value));
        }
Example #13
0
        private void SetEpmValueForSegment(EntityPropertyMappingInfo epmInfo, int propertyValuePathIndex, IEdmStructuredTypeReference segmentStructuralTypeReference, List<ODataProperty> existingProperties, object propertyValue)
        {
            string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName;
            if (!epmInfo.Attribute.KeepInContent)
            {
                IEdmTypeReference type;
                ODataProperty property = existingProperties.FirstOrDefault<ODataProperty>(p => string.CompareOrdinal(p.Name, propertyName) == 0);
                ODataComplexValue value2 = null;
                if (property != null)
                {
                    value2 = property.Value as ODataComplexValue;
                    if (value2 == null)
                    {
                        return;
                    }
                }
                IEdmProperty property2 = segmentStructuralTypeReference.FindProperty(propertyName);
                if ((property2 == null) && (propertyValuePathIndex != (epmInfo.PropertyValuePath.Length - 1)))
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath));
                }
                if ((property2 == null) || (this.MessageReaderSettings.DisablePrimitiveTypeConversion && property2.Type.IsODataPrimitiveTypeKind()))
                {
                    type = EdmCoreModel.Instance.GetString(true);
                }
                else
                {
                    type = property2.Type;
                }
                switch (type.TypeKind())
                {
                    case EdmTypeKind.Primitive:
                        object obj2;
                        if (type.IsStream())
                        {
                            throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty));
                        }
                        if (propertyValue == null)
                        {
                            ReaderValidationUtils.ValidateNullValue(this.atomInputContext.Model, type, this.atomInputContext.MessageReaderSettings, true, this.atomInputContext.Version);
                            obj2 = null;
                        }
                        else
                        {
                            obj2 = AtomValueUtils.ConvertStringToPrimitive((string) propertyValue, type.AsPrimitive());
                        }
                        this.AddEpmPropertyValue(existingProperties, propertyName, obj2, segmentStructuralTypeReference.IsODataEntityTypeKind());
                        return;

                    case EdmTypeKind.Complex:
                    {
                        if (value2 == null)
                        {
                            value2 = new ODataComplexValue {
                                TypeName = type.ODataFullName(),
                                Properties = new ReadOnlyEnumerable<ODataProperty>()
                            };
                            this.AddEpmPropertyValue(existingProperties, propertyName, value2, segmentStructuralTypeReference.IsODataEntityTypeKind());
                        }
                        IEdmComplexTypeReference reference2 = type.AsComplex();
                        this.SetEpmValueForSegment(epmInfo, propertyValuePathIndex + 1, reference2, ReaderUtils.GetPropertiesList(value2.Properties), propertyValue);
                        return;
                    }
                    case EdmTypeKind.Collection:
                    {
                        ODataCollectionValue value4 = new ODataCollectionValue {
                            TypeName = type.ODataFullName(),
                            Items = new ReadOnlyEnumerable((List<object>) propertyValue)
                        };
                        this.AddEpmPropertyValue(existingProperties, propertyName, value4, segmentStructuralTypeReference.IsODataEntityTypeKind());
                        return;
                    }
                }
                throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind));
            }
        }
Example #14
0
        /// <summary>
        /// Adds a path to the source and target tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/>
        /// </summary>
        /// <param name="epmInfo">EnitityPropertyMappingInfo holding the source path</param>
        internal void Add(EntityPropertyMappingInfo epmInfo)
        {
            DebugUtils.CheckNoExternalCallers();

            List <EpmSourcePathSegment> pathToCurrentSegment = new List <EpmSourcePathSegment>();
            EpmSourcePathSegment        currentSourceSegment = this.Root;
            EpmSourcePathSegment        foundSourceSegment   = null;
            IEdmType currentType = epmInfo.ActualPropertyType;

            Debug.Assert(!string.IsNullOrEmpty(epmInfo.Attribute.SourcePath), "Invalid source path");
            string[] propertyPath = epmInfo.Attribute.SourcePath.Split('/');

            int propertyPathLength = propertyPath.Length;

            Debug.Assert(propertyPathLength > 0, "Must have been validated during EntityPropertyMappingAttribute construction");
            for (int sourcePropertyIndex = 0; sourcePropertyIndex < propertyPathLength; sourcePropertyIndex++)
            {
                string propertyName = propertyPath[sourcePropertyIndex];

                if (propertyName.Length == 0)
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }

                IEdmTypeReference nextPropertyTypeReference = GetPropertyType(currentType, propertyName);
                IEdmType          nextPropertyType          = nextPropertyTypeReference == null ? null : nextPropertyTypeReference.Definition;

                // If we don't find a property type this is an open property; check whether this is the last segment in the path
                // since otherwise this would not be an open primitive property and only open primitive properties are allowed.
                if (nextPropertyType == null && sourcePropertyIndex < propertyPathLength - 1)
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, currentType.ODataFullName()));
                }

                currentType        = nextPropertyType;
                foundSourceSegment = currentSourceSegment.SubProperties.SingleOrDefault(e => e.PropertyName == propertyName);
                if (foundSourceSegment != null)
                {
                    currentSourceSegment = foundSourceSegment;
                }
                else
                {
                    EpmSourcePathSegment newSourceSegment = new EpmSourcePathSegment(propertyName);
                    currentSourceSegment.SubProperties.Add(newSourceSegment);
                    currentSourceSegment = newSourceSegment;
                }

                pathToCurrentSegment.Add(currentSourceSegment);
            }

            // The last segment is the one being mapped from by the user specified attribute.
            // It must be a primitive type - we don't allow mappings of anything else than primitive properties directly.
            // Note that we can only verify this for non-open properties, for open properties we must assume it's a primitive type
            // and we will make this check later during serialization again when we actually have the value of the property.
            if (currentType != null)
            {
                if (!currentType.IsODataPrimitiveTypeKind())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_EndsWithNonPrimitiveType(currentSourceSegment.PropertyName));
                }
            }

            Debug.Assert(foundSourceSegment == null || foundSourceSegment.EpmInfo != null, "Can't have a leaf node in the tree without EpmInfo.");

            // Two EpmAttributes with same PropertyName in the same type, this could be a result of inheritance
            if (foundSourceSegment != null)
            {
                Debug.Assert(object.ReferenceEquals(foundSourceSegment, currentSourceSegment), "currentSourceSegment variable should have been updated already to foundSourceSegment");

                // Check for duplicates on the same entity type
                Debug.Assert(foundSourceSegment.SubProperties.Count == 0, "If non-leaf, it means we allowed complex type to be a leaf node");
                if (foundSourceSegment.EpmInfo.DefiningTypesAreEqual(epmInfo))
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath));
                }

                // In case of inheritance, we need to remove the node from target tree which was mapped to base type property
                this.epmTargetTree.Remove(foundSourceSegment.EpmInfo);
            }

            epmInfo.SetPropertyValuePath(pathToCurrentSegment.ToArray());
            currentSourceSegment.EpmInfo = epmInfo;

            this.epmTargetTree.Add(epmInfo);
        }
Example #15
0
        /// <summary>
        /// Sets the value read from EPM to a property on an entry.
        /// </summary>
        /// <param name="targetList">The target list, which is a list of properties (on entry or complex value).</param>
        /// <param name="targetTypeReference">The type of the value on which to set the property (can be entity or complex).</param>
        /// <param name="epmInfo">The EPM info for the mapping for which the value was read.</param>
        /// <param name="propertyValue">The property value read, if the value was specified as null then this should be null,
        /// if the value was missing the method should not be called at all.
        /// For primitive properties this should be the string value, for all other properties this should be the exact value type.</param>
        protected void SetEpmValue(
            IList targetList,
            IEdmTypeReference targetTypeReference,
            EntityPropertyMappingInfo epmInfo,
            object propertyValue)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(targetTypeReference != null, "targetTypeReference != null");
            Debug.Assert(targetList != null, "targetList != null");
            Debug.Assert(
                targetTypeReference.IsODataEntityTypeKind() || targetTypeReference.IsODataComplexTypeKind(),
                "Only entity and complex types can have an EPM value set on them.");

            this.SetEpmValueForSegment(
                epmInfo,
                0,
                targetTypeReference.AsStructuredOrNull(),
                (List<ODataProperty>)targetList,
                propertyValue);
        }
 internal bool Contains(EntityPropertyMappingInfo epmInfo)
 {
     return this.customEpmValues.Any<KeyValuePair<EntityPropertyMappingInfo, string>>(epmValue => object.ReferenceEquals(epmValue.Key, epmInfo));
 }
 internal bool DefiningTypesAreEqual(EntityPropertyMappingInfo other)
 {
     return(((IEdmType)this.DefiningType).IsEquivalentTo(((IEdmType)other.DefiningType)));
 }
Example #18
0
 protected object ReadEntryPropertyValue(EntityPropertyMappingInfo epmInfo, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType)
 {
     return this.ReadPropertyValue(epmInfo, epmValueCache.EntryProperties, 0, entityType, epmValueCache);
 }
Example #19
0
        /// <summary>
        /// Reads a property value starting with the specified index to the property value path.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="cachedProperties">The enumeration of properties to search for the first property in the property value path.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="structuredTypeReference">The type of the entry or complex value the <paramref name="cachedProperties"/> enumeration belongs to.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            IEnumerable<ODataProperty> cachedProperties,
            int sourceSegmentIndex,
            IEdmStructuredTypeReference structuredTypeReference,
            EpmValueCache epmValueCache)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(structuredTypeReference != null, "structuredTypeReference != null");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");

            EpmSourcePathSegment sourceSegment = epmInfo.PropertyValuePath[sourceSegmentIndex];
            string propertyName = sourceSegment.PropertyName;
            bool lastSegment = epmInfo.PropertyValuePath.Length == sourceSegmentIndex + 1;

            IEdmStructuredType structuredType = structuredTypeReference.StructuredDefinition();
            IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, structuredType);
            if (edmProperty != null)
            {
                // If this is the last part of the path, then it has to be a primitive or atomic collection type otherwise should be a complex type
                if (lastSegment)
                {
                    if (!edmProperty.Type.IsODataPrimitiveTypeKind() && !edmProperty.Type.IsNonEntityODataCollectionTypeKind())
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                }
                else
                {
                    if (edmProperty.Type.TypeKind() != EdmTypeKind.Complex)
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                    }
                }
            }
            else
            {
                Debug.Assert(
                    structuredType.IsOpen,
                    "Only open types can have undeclared properties, otherwise we should have failed in the ValidatePropertyDefined method.");
            }

            ODataProperty property = cachedProperties == null ? null : cachedProperties.FirstOrDefault(p => p.Name == propertyName);
            if (property == null)
            {
                throw new ODataException(o.Strings.EpmSourceTree_MissingPropertyOnInstance(propertyName, structuredTypeReference.ODataFullName()));
            }

            object propertyValue = property.Value;
            ODataComplexValue propertyComplexValue = propertyValue as ODataComplexValue;
            if (lastSegment)
            {
                if (propertyValue == null)
                {
                    WriterValidationUtils.ValidateNullPropertyValue(edmProperty, this.WriterBehavior, this.atomOutputContext.Model);
                }
                else
                {
                    // If this property is the last one it has to be either a primitive or collection
                    if (propertyComplexValue != null)
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                    else
                    {
                        ODataCollectionValue propertyCollectionValue = propertyValue as ODataCollectionValue;
                        if (propertyCollectionValue != null)
                        {
                            // Validate the type name for the collection
                            string typeName = propertyCollectionValue.TypeName;
                            WriterValidationUtils.ResolveTypeNameForWriting(
                                this.atomOutputContext.Model,
                                edmProperty == null ? null : edmProperty.Type,
                                ref typeName,
                                EdmTypeKind.Collection,
                                edmProperty == null);
                        }
                        else
                        {
                            if (propertyValue is ODataStreamReferenceValue)
                            {
                                // Stream properties should not come here, if it were an ODataEntry property it would have been 
                                // filtered in ReadEntryPropertyValue() by "epmValueCache.EntryProperties" call.
                                throw new ODataException(o.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                            }
                            else if (propertyValue is ISpatial)
                            {
                                throw new ODataException(o.Strings.EpmSourceTree_OpenPropertySpatialTypeCannotBeMapped(propertyName, epmInfo.DefiningType.FullName()));
                            }
                            else if (edmProperty != null)
                            {
                                ValidationUtils.ValidateIsExpectedPrimitiveType(propertyValue, edmProperty.Type);
                            }
                        }
                    }
                }

                return propertyValue;
            }

            // Otherwise it's in the middle and thus it must be a complex value
            if (propertyComplexValue == null)
            {
                if (propertyValue != null)
                {
                    // It's not a complex value - fail.
                    throw new ODataException(o.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                }
                else
                {
                    // The value of the property is null, which can be a null complex value
                    // Note that we must not attempt to resolve the type as if the type name was null here, because
                    //  1) We don't need the type for anything anyway (the value is null, this is the end)
                    //  2) If the property is open, trying to resolve a null type name would throw
                    //     but we don't have a null type name, we have a null entire value.
                    return null;
                }
            }

            string localTypeName = propertyComplexValue.TypeName;
            IEdmComplexTypeReference complexValueType = WriterValidationUtils.ResolveTypeNameForWriting(
                this.atomOutputContext.Model,
                edmProperty == null ? null : edmProperty.Type,
                ref localTypeName,
                EdmTypeKind.Complex,
                edmProperty == null).AsComplexOrNull();

            return this.ReadComplexPropertyValue(
                epmInfo,
                propertyComplexValue,
                epmValueCache,
                sourceSegmentIndex + 1,
                complexValueType);
        }
Example #20
0
        private void SetEpmValueForSegment(
            EntityPropertyMappingInfo epmInfo,
            int propertyValuePathIndex,
            IEdmStructuredTypeReference segmentStructuralTypeReference,
            List<ODataProperty> existingProperties,
            object propertyValue)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(propertyValuePathIndex < epmInfo.PropertyValuePath.Length, "The propertyValuePathIndex is out of bounds.");
            Debug.Assert(existingProperties != null, "existingProperties != null");

            string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName;

            // Do not set out-of-content values if the EPM is defined as KeepInContent=true.
            if (epmInfo.Attribute.KeepInContent)
            {
                return;
            }

            // Try to find the property in the existing properties
            // If the property value is atomic from point of view of EPM (non-streaming collection or primitive) then if it already exists
            // it must have been in-content, and thus we leave it as is (note that two EPMs can't map to the same property, we verify that upfront).
            // If the property value is non-atomic, then it is a complex value, we might want to merge the new value comming from EPM with it.
            ODataProperty existingProperty = existingProperties.FirstOrDefault(p => string.CompareOrdinal(p.Name, propertyName) == 0);
            ODataComplexValue existingComplexValue = null;
            if (existingProperty != null)
            {
                // In case the property exists and it's a complex value we will try to merge.
                // Note that if the property is supposed to be complex, but it already has a null value, then the null wins.
                // Since in-content null complex value wins over any EPM complex value.
                existingComplexValue = existingProperty.Value as ODataComplexValue;
                if (existingComplexValue == null)
                {
                    return;
                }
            }

            IEdmProperty propertyMetadata = segmentStructuralTypeReference.FindProperty(propertyName);
            Debug.Assert(propertyMetadata != null || segmentStructuralTypeReference.IsOpen(), "We should have verified that if the property is not declared the type must be open.");

            if (propertyMetadata == null && propertyValuePathIndex != epmInfo.PropertyValuePath.Length - 1)
            {
                throw new ODataException(o.Strings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath));
            }

            // Open properties in EPM are by default of type Edm.String - there's no way to specify a typename in EPM
            // consumer is free to do the conversion later on if it needs to.
            // Note that this effectively means that ODataMessageReaderSettings.DisablePrimitiveTypeConversion is as if it's turned on for open EPM properties.
            IEdmTypeReference propertyType;
            if (propertyMetadata == null ||
                (this.MessageReaderSettings.DisablePrimitiveTypeConversion && propertyMetadata.Type.IsODataPrimitiveTypeKind()))
            {
                propertyType = EdmCoreModel.Instance.GetString(/*nullable*/true);
            }
            else
            {
                propertyType = propertyMetadata.Type;
            }

            // NOTE: WCF DS Server only applies the values when
            // - It's an open property
            // - It's not a key property
            // - It's a key property and it's a POST operation
            // ODataLib here will always set the property though.
            switch (propertyType.TypeKind())
            {
                case EdmTypeKind.Primitive:
                    {
                        if (propertyType.IsStream())
                        {
                            throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty));
                        }

                        object primitiveValue;
                        if (propertyValue == null)
                        {
                            ReaderValidationUtils.ValidateNullValue(this.atomInputContext.Model, propertyType, this.atomInputContext.MessageReaderSettings, /*validateNullValue*/ true, this.atomInputContext.Version);
                            primitiveValue = null;
                        }
                        else
                        {
                            // Convert the value to the desired target type
                            primitiveValue = AtomValueUtils.ConvertStringToPrimitive((string)propertyValue, propertyType.AsPrimitive());
                        }

                        this.AddEpmPropertyValue(existingProperties, propertyName, primitiveValue, segmentStructuralTypeReference.IsODataEntityTypeKind());
                    }

                    break;

                case EdmTypeKind.Complex:
                    // Note: Unlike WCF DS we don't have a preexisting instance to override (since complex values are atomic, so we should not updated them)
                    // In our case the complex value either doesn't exist yet on the entry being reported (easy, create it)
                    // or it exists, but then it was created during reading of previous normal or EPM properties for this entry. It never exists before
                    // we ever get to see the entity. So in our case we will never recreate the complex value, we always start with new one
                    // and update it with new properties as they come. (Next time we will start over with a new complex value.)
                    Debug.Assert(
                        existingComplexValue == null || (existingProperty != null && existingProperty.Value == existingComplexValue),
                        "If we have existing complex value, we must have an existing property as well.");
                    Debug.Assert(
                        epmInfo.PropertyValuePath.Length > propertyValuePathIndex + 1,
                        "Complex value can not be a leaf segment in the source property path. We should have failed constructing the EPM trees for it.");

                    if (existingComplexValue == null)
                    {
                        Debug.Assert(existingProperty == null, "If we don't have an existing complex value, then we must not have an existing property at all.");

                        // Create a new complex value and set its type name to the type name of the property type (in case of EPM we never have type name from the payload)
                        existingComplexValue = new ODataComplexValue
                        {
                            TypeName = propertyType.ODataFullName(),
                            Properties = new ReadOnlyEnumerable<ODataProperty>()
                        };

                        this.AddEpmPropertyValue(existingProperties, propertyName, existingComplexValue, segmentStructuralTypeReference.IsODataEntityTypeKind());
                    }

                    // Get the properties list of the complex value and recursively set the next EPM segment value to it.
                    // Note that on inner complex value we don't need to check for duplicate properties
                    // because EPM will never add a property which already exists (see the start of this method).
                    IEdmComplexTypeReference complexPropertyTypeReference = propertyType.AsComplex();
                    Debug.Assert(complexPropertyTypeReference != null, "complexPropertyTypeReference != null");
                    this.SetEpmValueForSegment(
                        epmInfo,
                        propertyValuePathIndex + 1,
                        complexPropertyTypeReference,
                        ReaderUtils.GetPropertiesList(existingComplexValue.Properties),
                        propertyValue);

                    break;

                case EdmTypeKind.Collection:
                    Debug.Assert(propertyType.IsNonEntityODataCollectionTypeKind(), "Collection types in EPM must be atomic.");

                    // In this case the property value is the internal list of items.
                    // Create a new collection value and set the list as the list of items on it.
                    ODataCollectionValue collectionValue = new ODataCollectionValue
                    {
                        TypeName = propertyType.ODataFullName(),
                        Items = new ReadOnlyEnumerable((List<object>)propertyValue)
                    };

                    this.AddEpmPropertyValue(existingProperties, propertyName, collectionValue, segmentStructuralTypeReference.IsODataEntityTypeKind());

                    break;
                default:
                    throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind));
            }
        }
Example #21
0
        internal void Add(EntityPropertyMappingInfo epmInfo)
        {
            string targetPath            = epmInfo.Attribute.TargetPath;
            string namespaceUri          = epmInfo.Attribute.TargetNamespaceUri;
            string targetNamespacePrefix = epmInfo.Attribute.TargetNamespacePrefix;
            EpmTargetPathSegment         parentSegment = epmInfo.IsSyndicationMapping ? this.SyndicationRoot : this.NonSyndicationRoot;
            IList <EpmTargetPathSegment> subSegments   = parentSegment.SubSegments;

            string[]             strArray = targetPath.Split(new char[] { '/' });
            EpmTargetPathSegment segment2 = null;

            for (int i = 0; i < strArray.Length; i++)
            {
                string targetSegment = strArray[i];
                if (targetSegment.Length == 0)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_InvalidTargetPath_EmptySegment(targetPath));
                }
                if ((targetSegment[0] == '@') && (i != (strArray.Length - 1)))
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_AttributeInMiddle(targetSegment));
                }
                segment2 = subSegments.SingleOrDefault <EpmTargetPathSegment>(delegate(EpmTargetPathSegment segment) {
                    if (!(segment.SegmentName == targetSegment))
                    {
                        return(false);
                    }
                    if (!epmInfo.IsSyndicationMapping)
                    {
                        return(segment.SegmentNamespaceUri == namespaceUri);
                    }
                    return(true);
                });
                if (segment2 != null)
                {
                    parentSegment = segment2;
                }
                else
                {
                    parentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, targetNamespacePrefix, parentSegment);
                    if (targetSegment[0] == '@')
                    {
                        subSegments.Insert(0, parentSegment);
                    }
                    else
                    {
                        subSegments.Add(parentSegment);
                    }
                }
                subSegments = parentSegment.SubSegments;
            }
            if (parentSegment.EpmInfo != null)
            {
                throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_DuplicateEpmAttributesWithSameTargetName(parentSegment.EpmInfo.DefiningType.ODataFullName(), GetPropertyNameFromEpmInfo(parentSegment.EpmInfo), parentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath));
            }
            if (!epmInfo.Attribute.KeepInContent)
            {
                this.countOfNonContentV2Mappings++;
            }
            parentSegment.EpmInfo = epmInfo;
            List <EntityPropertyMappingAttribute> ancestorsWithContent = new List <EntityPropertyMappingAttribute>(2);

            if (HasMixedContent(this.NonSyndicationRoot, ancestorsWithContent))
            {
                throw new ODataException(Microsoft.Data.OData.Strings.EpmTargetTree_InvalidTargetPath_MixedContent(ancestorsWithContent[0].TargetPath, ancestorsWithContent[1].TargetPath));
            }
        }
Example #22
0
 /// <summary>
 /// Sets the value read from EPM to a property on an entry.
 /// </summary>
 /// <param name="epmInfo">The EPM info for the mapping for which the value was read.</param>
 /// <param name="propertyValue">The property value read, if the value was specified as null then this should be null,
 /// if the value was missing the method should not be called at all.
 /// For primitive properties this should be the string value, for all other properties this should be the exact value type.</param>
 protected void SetEntryEpmValue(EntityPropertyMappingInfo epmInfo, object propertyValue)
 {
     this.SetEpmValue(
         ReaderUtils.GetPropertiesList(this.entryState.Entry.Properties),
         this.entryState.EntityType.ToTypeReference(),
         epmInfo,
         propertyValue);
 }
Example #23
0
 private object ReadComplexPropertyValue(EntityPropertyMappingInfo epmInfo, ODataComplexValue complexValue, EpmValueCache epmValueCache, int sourceSegmentIndex, IEdmComplexTypeReference complexType)
 {
     return this.ReadPropertyValue(epmInfo, EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false), sourceSegmentIndex, complexType, epmValueCache);
 }
Example #24
0
        /// <summary>
        /// Reads a property value starting on a complex value.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="complexValue">The complex value to start with.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="complexType">The type of the complex value.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadComplexPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            ODataComplexValue complexValue,
            EpmValueCache epmValueCache,
            int sourceSegmentIndex,
            IEdmComplexTypeReference complexType)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(sourceSegmentIndex >= 0, "sourceSegmentIndex >= 0");
            Debug.Assert(complexType != null, "complexType != null");
            Debug.Assert(complexValue != null, "complexValue != null");

            return this.ReadPropertyValue(
                epmInfo,
                EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false),
                sourceSegmentIndex,
                complexType,
                epmValueCache);
        }
Example #25
0
 private object ReadPropertyValue(EntityPropertyMappingInfo epmInfo, IEnumerable<ODataProperty> cachedProperties, int sourceSegmentIndex, IEdmStructuredTypeReference structuredTypeReference, EpmValueCache epmValueCache)
 {
     EpmSourcePathSegment segment = epmInfo.PropertyValuePath[sourceSegmentIndex];
     string propertyName = segment.PropertyName;
     bool flag = epmInfo.PropertyValuePath.Length == (sourceSegmentIndex + 1);
     IEdmStructuredType owningStructuredType = structuredTypeReference.StructuredDefinition();
     IEdmProperty expectedProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningStructuredType);
     if (expectedProperty != null)
     {
         if (flag)
         {
             if (!expectedProperty.Type.IsODataPrimitiveTypeKind() && !expectedProperty.Type.IsNonEntityODataCollectionTypeKind())
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
             }
         }
         else if (expectedProperty.Type.TypeKind() != EdmTypeKind.Complex)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
         }
     }
     ODataProperty property2 = (cachedProperties == null) ? null : cachedProperties.FirstOrDefault<ODataProperty>(p => (p.Name == propertyName));
     if (property2 == null)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnInstance(propertyName, structuredTypeReference.ODataFullName()));
     }
     object obj2 = property2.Value;
     ODataComplexValue complexValue = obj2 as ODataComplexValue;
     if (flag)
     {
         if (obj2 == null)
         {
             WriterValidationUtils.ValidateNullPropertyValue(expectedProperty, this.WriterBehavior, this.atomOutputContext.Model);
             return obj2;
         }
         if (complexValue != null)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
         }
         ODataCollectionValue value3 = obj2 as ODataCollectionValue;
         if (value3 != null)
         {
             string str = value3.TypeName;
             WriterValidationUtils.ResolveTypeNameForWriting(this.atomOutputContext.Model, (expectedProperty == null) ? null : expectedProperty.Type, ref str, EdmTypeKind.Collection, expectedProperty == null);
             return obj2;
         }
         if (obj2 is ODataStreamReferenceValue)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
         }
         if (obj2 is ISpatial)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenPropertySpatialTypeCannotBeMapped(propertyName, epmInfo.DefiningType.FullName()));
         }
         if (expectedProperty != null)
         {
             ValidationUtils.ValidateIsExpectedPrimitiveType(obj2, expectedProperty.Type);
         }
         return obj2;
     }
     if (complexValue == null)
     {
         if (obj2 != null)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
         }
         return null;
     }
     string typeName = complexValue.TypeName;
     IEdmComplexTypeReference complexType = WriterValidationUtils.ResolveTypeNameForWriting(this.atomOutputContext.Model, (expectedProperty == null) ? null : expectedProperty.Type, ref typeName, EdmTypeKind.Complex, expectedProperty == null).AsComplexOrNull();
     return this.ReadComplexPropertyValue(epmInfo, complexValue, epmValueCache, sourceSegmentIndex + 1, complexType);
 }
 internal void Add(EntityPropertyMappingInfo epmInfo, string value)
 {
     this.customEpmValues.Add(new KeyValuePair<EntityPropertyMappingInfo, string>(epmInfo, value));
 }