/// <summary>Adds the null valued properties to the content section of a syndication entry</summary> /// <param name="currentRoot">Current root node</param> /// <param name="currentContent">Current collection to which property is to be added</param> private void AddNullValuesToContent(EpmNullValuedPropertyNode currentRoot, DictionaryContent currentContent) { foreach (EpmNullValuedPropertyNode node in currentRoot.Children) { bool found; DictionaryContent c = currentContent.Lookup(node.Name, out found); Debug.Assert(node.ResourceType != null, "node.ResourceType != null"); switch (node.ResourceType.ResourceTypeKind) { case ResourceTypeKind.ComplexType: if (!found) { // If a complex property is not found in content, it is either not being projected // or all of its properties are mapped and all of them have KeepInContent=false Debug.Assert(c == null, "when look up not found, c should be null."); if (node.Element != null) { Debug.Assert(node.Children.Count > 0, "If the property represented by the current node is not null, there must be children nodes."); // The complex property is not null, but some of its descendant properties are null. // We need to serialize the type name of the complex property. c = new DictionaryContent(); currentContent.Add(node.Name, node.ResourceType.FullName, c); } else { Debug.Assert(node.Children.Count == 0, "If the property represented by the current node is not null, there must not be any children node."); // The complex property is null, we write out m:null='true'. currentContent.AddNull(node.ResourceType.FullName, node.Name); } } if (c != null) { // Only add the children properties if the complex property is not null. this.AddNullValuesToContent(node, c); } break; case ResourceTypeKind.Primitive: Debug.Assert(c == null, "DictionaryContent not expected for primitive properties."); Debug.Assert(node.Element == null, "node.Element == null"); if (!found) { currentContent.AddNull(node.ResourceType.FullName, node.Name); } // if found, use the value in currentContent, we don't need to do anything here. break; case ResourceTypeKind.EntityType: Debug.Assert(false, "We cannot map navigation properties with friendly feeds."); break; } } }
/// <summary>Constructor that creates the root of the tree</summary> /// <param name="provider">Provider wrapper instance</param> /// <param name="element">Object whose properties we will read</param> internal EpmNullValuedPropertyTree(DataServiceProviderWrapper provider, object element) { this.root = new EpmNullValuedPropertyNode { Name = null }; this.provider = provider; this.element = element; }
/// <summary>Adds a property to the null valued collection</summary> /// <param name="epmInfo">EpmInfo containing the property information such as path</param> internal void Add(EntityPropertyMappingInfo epmInfo) { Debug.Assert(epmInfo != null, "epmInfo != null"); EpmNullValuedPropertyNode current = this.root; ResourceType currentType = epmInfo.DefiningType; object currentValue = this.element; // We are here because the epm path points to a null value. If the path is multiple level deep, we need to // know the first level the null value begins and we don't need to serialize deeper than that. // To serialize the complex properties correctly in the case they are not already in content, we also need // to find the type for each segment from root to the first segment that has the null property value. foreach (var segment in epmInfo.Attribute.SourcePath.Split('/')) { EpmNullValuedPropertyNode child = current.Children.FirstOrDefault(c => c.Name == segment); if (child != null) { // The current segment is already added to the tree, reuse it. current = child; currentValue = child.Element; currentType = child.ResourceType; } else { EpmNullValuedPropertyNode newNode = new EpmNullValuedPropertyNode { Name = segment }; Debug.Assert(currentType != null, "currentType != null"); ResourceProperty property = currentType.TryResolvePropertyName(segment); Debug.Assert(currentValue != null, "currentValue != null"); ProjectedWrapper projectedValue = currentValue as ProjectedWrapper; if (projectedValue == null) { if (property != null) { currentValue = this.provider.GetPropertyValue(currentValue, property, currentType); currentValue = currentValue == DBNull.Value ? null : currentValue; currentType = property.ResourceType; } else { // Handle open property... currentValue = this.provider.GetOpenPropertyValue(currentValue, segment); currentValue = currentValue == DBNull.Value ? null : currentValue; if (currentValue != null) { // Get the type from the instance. currentType = this.provider.GetResourceType(currentValue); } else { // We have a null open property at hand, we don't know its type. // Default the type to string so that we will omit the type name // and just write out null. i.e. <d:prop m:null='true'/> currentType = ResourceType.PrimitiveStringResourceType; } } } else { currentValue = projectedValue.GetProjectedPropertyValue(segment); currentValue = currentValue == DBNull.Value ? null : currentValue; if (property != null) { currentType = property.ResourceType; } else { // Handle open property... if (currentValue == null) { // We have a null open property at hand, we don't know its type. // Default the type to string so that we will omit the type name // and just write out null. i.e. <d:prop m:null='true'/> currentType = ResourceType.PrimitiveStringResourceType; } else { projectedValue = currentValue as ProjectedWrapper; if (projectedValue != null) { // Get the type from the project wrapper. currentType = this.provider.TryResolveResourceType(projectedValue.ResourceTypeName); } else { // Get the type from the instance. currentType = this.provider.GetResourceType(currentValue); } } } } Debug.Assert(currentType != null, "currentType != null"); Debug.Assert(currentValue != DBNull.Value, "currentValue != DBNull.Value -- we have converted DBNull to null"); newNode.ResourceType = currentType; newNode.Element = currentValue; current.Children.Add(newNode); current = newNode; } if (current.Element == null) { // If the current element is null, we don't need to go further since that is the obvious reason // that the children properties are null. break; } } }