static OrderBySetting FindProperties(IEdmEntityType entity)
            {
                var propertyNames = entity.Key().Any() switch
                {
                    true => entity.Key().Select(k => k.Name),
                    false => entity.StructuralProperties()
                    .Where(p => p.Type.IsPrimitive() && !p.Type.IsStream())
                    .Select(p => p.Name)
                    .OrderBy(n => n)
                    .Take(1)
                };
                var orderBySettings = new OrderBySetting();

                propertyNames.Aggregate(orderBySettings, (settings, name) =>
                {
                    if (settings.Name is null)
                    {
                        settings.Name = name;
                        return(settings);
                    }
                    settings.ThenBy = new() { Name = name };
                    return(settings.ThenBy);
                });
                return(orderBySettings.Name is null ? null : orderBySettings);
            }
        }
    }
Ejemplo n.º 2
0
        /// <summary>
        /// Create key parameters for the <see cref="ODataKeySegment"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="keySegment">The key segment.</param>
        /// <param name="parameterNameMapping">The parameter name mapping.</param>
        /// <returns>The created the list of <see cref="OpenApiParameter"/>.</returns>
        public static IList <OpenApiParameter> CreateKeyParameters(this ODataContext context, ODataKeySegment keySegment,
                                                                   IDictionary <string, string> parameterNameMapping = null)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(keySegment, nameof(keySegment));

            IList <OpenApiParameter> parameters = new List <OpenApiParameter>();
            IEdmEntityType           entityType = keySegment.EntityType;

            IList <IEdmStructuralProperty> keys = entityType.Key().ToList();

            if (keys.Count() == 1)
            {
                string keyName = keys.First().Name;

                // If dictionary parameterNameMapping is defined, there's no need of setting the
                // keyName, we will retrieve this from the dictionary key.
                if (context.Settings.PrefixEntityTypeNameBeforeKey && parameterNameMapping == null)
                {
                    keyName = entityType.Name + "-" + keys.First().Name;
                }

                OpenApiParameter parameter = new OpenApiParameter
                {
                    Name        = parameterNameMapping == null ? keyName: parameterNameMapping[keyName],
                    In          = ParameterLocation.Path,
                    Required    = true,
                    Description = "key: " + keyName + " of " + entityType.Name,
                    Schema      = context.CreateEdmTypeSchema(keys.First().Type)
                };

                parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                parameters.Add(parameter);
            }
            else
            {
                // append key parameter
                foreach (var keyProperty in entityType.Key())
                {
                    OpenApiParameter parameter = new OpenApiParameter
                    {
                        Name = parameterNameMapping == null ?
                               keyProperty.Name:
                               parameterNameMapping[keyProperty.Name],// By design: not prefix with type name if enable type name prefix
                        In          = ParameterLocation.Path,
                        Required    = true,
                        Description = "key: " + keyProperty.Name + " of " + entityType.Name,
                        Schema      = context.CreateEdmTypeSchema(keyProperty.Type)
                    };

                    parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                    parameters.Add(parameter);
                }
            }

            return(parameters);
        }
Ejemplo n.º 3
0
        /// <inheritdoc />
        public override bool TryTranslate(ODataTemplateTranslateContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            RouteValueDictionary routeValues = context.RouteValues;

            // the request should have the navigation property
            if (!routeValues.TryGetValue(ParameterName, out object rawValue))
            {
                return(false);
            }

            string navigationProperty = rawValue as string;

            if (navigationProperty == null)
            {
                return(false);
            }

            // Find the navigation property
            IEdmNavigationProperty edmNavProperty = DeclaringType.ResolveProperty(navigationProperty) as IEdmNavigationProperty;

            if (edmNavProperty == null)
            {
                return(false);
            }

            IEdmNavigationSource targetNavigationSource = NavigationSource.FindNavigationTarget(edmNavProperty);

            // ODL implementation is complex, here i just use the NavigationPropertyLinkSegment
            context.Segments.Add(new NavigationPropertyLinkSegment(edmNavProperty, targetNavigationSource));

            if (RelatedKey != null)
            {
                IEdmEntityType entityType = edmNavProperty.ToEntityType();

                // only handle the single key
                IEdmStructuralProperty keyProperty = entityType.Key().SingleOrDefault();
                Contract.Assert(entityType.Key().Count() == 1);
                Contract.Assert(keyProperty != null);

                IDictionary <string, string> keyValuePairs = new Dictionary <string, string>
                {
                    { keyProperty.Name, $"{{{RelatedKey}}}" }
                };

                KeySegmentTemplate keySegment = new KeySegmentTemplate(keyValuePairs, entityType, targetNavigationSource);
                return(keySegment.TryTranslate(context));
            }

            return(true);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Create key parameters for the <see cref="ODataKeySegment"/>.
        /// </summary>
        /// <param name="keySegment">The key segment.</param>
        /// <returns>The created the list of <see cref="OpenApiParameter"/>.</returns>
        public static IList <OpenApiParameter> CreateKeyParameters(this ODataContext context, ODataKeySegment keySegment)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(keySegment, nameof(keySegment));

            IList <OpenApiParameter> parameters = new List <OpenApiParameter>();
            IEdmEntityType           entityType = keySegment.EntityType;

            IList <IEdmStructuralProperty> keys = entityType.Key().ToList();

            if (keys.Count() == 1)
            {
                string keyName = keys.First().Name + keySegment.KeyIndex.ToString();
                if (context.Settings.PrefixEntityTypeNameBeforeKey)
                {
                    keyName = entityType.Name + "-" + keyName;
                }

                OpenApiParameter parameter = new OpenApiParameter
                {
                    Name        = keyName,
                    In          = ParameterLocation.Path,
                    Required    = true,
                    Description = "key: " + keyName,
                    Schema      = context.CreateEdmTypeSchema(keys.First().Type)
                };

                parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                parameters.Add(parameter);
            }
            else
            {
                // append key parameter
                foreach (var keyProperty in entityType.Key())
                {
                    string keyName = keyProperty.Name + keySegment.KeyIndex.ToString();

                    OpenApiParameter parameter = new OpenApiParameter
                    {
                        Name        = keyName,
                        In          = ParameterLocation.Path,
                        Required    = true,
                        Description = "key: " + keyName,
                        Schema      = context.CreateEdmTypeSchema(keyProperty.Type)
                    };

                    parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                    parameters.Add(parameter);
                }
            }

            return(parameters);
        }
Ejemplo n.º 5
0
        // new CollectionWrapper<ElementType> { Instance = source.Select((ElementType element) => new Wrapper { }) }
        private Expression ProjectCollection(Expression source, Type elementType, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmEntitySet entitySet)
        {
            ParameterExpression element = Expression.Parameter(elementType);

            // expression
            //      new Wrapper { }
            Expression projection = ProjectElement(element, selectExpandClause, entityType, entitySet);

            // expression
            //      (ElementType element) => new Wrapper { }
            LambdaExpression selector = Expression.Lambda(projection, element);

            if (_settings.PageSize != null && _settings.PageSize.HasValue)
            {
                // nested paging. Need to apply order by first, and take one more than page size as we need to know
                // whether the collection was truncated or not while generating next page links.
                IEnumerable <IEdmStructuralProperty> properties =
                    entityType.Key().Any()
                        ? entityType.Key()
                        : entityType
                    .StructuralProperties()
                    .Where(property => property.Type.IsPrimitive()).OrderBy(property => property.Name);
                bool alreadyOrdered = false;
                foreach (var prop in properties)
                {
                    source = ExpressionHelpers.OrderByPropertyExpression(source, prop.Name, elementType, alreadyOrdered);
                    if (!alreadyOrdered)
                    {
                        alreadyOrdered = true;
                    }
                }

                source = ExpressionHelpers.Take(source, _settings.PageSize.Value + 1, elementType, _settings.EnableConstantParameterization);
            }

            // expression
            //      source.Select((ElementType element) => new Wrapper { })
            Expression selectedExpresion = Expression.Call(GetSelectMethod(elementType, projection.Type), source, selector);

            if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // source == null ? null : projectedCollection
                return(Expression.Condition(
                           test: Expression.Equal(source, Expression.Constant(null)),
                           ifTrue: Expression.Constant(null, selectedExpresion.Type),
                           ifFalse: selectedExpresion));
            }
            else
            {
                return(selectedExpresion);
            }
        }
        // Returns a sorted list of all properties that may legally appear
        // in an OrderBy.  If the entity type has keys, all are returned.
        // Otherwise, when no keys are present, all primitive properties are returned.
        private static IEnumerable <IEdmStructuralProperty> GetAvailableOrderByProperties(ODataQueryContext context)
        {
            Contract.Assert(context != null && context.EntitySet != null);

            IEdmEntityType entityType = context.EntitySet.ElementType;
            IEnumerable <IEdmStructuralProperty> properties =
                entityType.Key().Any()
                    ? entityType.Key()
                    : entityType
                .StructuralProperties()
                .Where(property => property.Type.IsPrimitive());

            // Sort properties alphabetically for stable sort
            return(properties.OrderBy(property => property.Name));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Binds a key property value.
        /// </summary>
        /// <param name="namedValue">The named value to bind.</param>
        /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param>
        /// <returns>The bound key property value node.</returns>
        private KeyPropertyValue BindKeyPropertyValue(NamedValue namedValue, IEdmEntityType collectionItemEntityType)
        {
            // These are exception checks because the data comes directly from the potentially user specified tree.
            ExceptionUtils.CheckArgumentNotNull(namedValue, "namedValue");
            ExceptionUtils.CheckArgumentNotNull(namedValue.Value, "namedValue.Value");
            Debug.Assert(collectionItemEntityType != null, "collectionItemType != null");

            IEdmProperty keyProperty = null;

            if (namedValue.Name == null)
            {
                foreach (IEdmProperty p in collectionItemEntityType.Key())
                {
                    if (keyProperty == null)
                    {
                        keyProperty = p;
                    }
                    else
                    {
                        throw new ODataException(ODataErrorStrings.MetadataBinder_UnnamedKeyValueOnTypeWithMultipleKeyProperties(collectionItemEntityType.ODataFullName()));
                    }
                }
            }
            else
            {
                keyProperty = collectionItemEntityType.Key().Where(k => string.CompareOrdinal(k.Name, namedValue.Name) == 0).SingleOrDefault();

                if (keyProperty == null)
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclaredOrNotKeyInKeyValue(namedValue.Name, collectionItemEntityType.ODataFullName()));
                }
            }

            IEdmTypeReference keyPropertyType = keyProperty.Type;

            SingleValueNode value = (SingleValueNode)this.keyValueBindMethod(namedValue.Value);

            // TODO: Check that the value is of primitive type
            Debug.Assert(keyPropertyType.IsODataPrimitiveTypeKind(), "The key's type must be primitive.");
            value = MetadataBindingUtils.ConvertToTypeIfNeeded(value, keyPropertyType);

            Debug.Assert(keyProperty != null, "keyProperty != null");
            return(new KeyPropertyValue()
            {
                KeyProperty = keyProperty,
                KeyValue = value
            });
        }
Ejemplo n.º 8
0
        public static IEdmStructuralProperty AssertHasKey(this IEdmEntityType entity, IEdmModel model, string keyName, EdmPrimitiveTypeKind primitiveTypeKind)
        {
            IEdmStructuralProperty key = entity.AssertHasPrimitiveProperty(model, keyName, primitiveTypeKind, isNullable: false);

            Assert.Contains(key, entity.Key());
            return(key);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Validates the <see cref="IEdmModel"/> that is being created.
        /// </summary>
        /// <param name="model">The <see cref="IEdmModel"/> that will be validated.</param>
        public virtual void ValidateModel(IEdmModel model)
        {
            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            // The type of entity set should have key(s) defined.
            foreach (IEdmEntitySet entitySet in model.EntityContainer.Elements.OfType <IEdmEntitySet>())
            {
                if (!entitySet.EntityType().Key().Any())
                {
                    throw Error.InvalidOperation(SRResources.EntitySetTypeHasNoKeys, entitySet.Name,
                                                 entitySet.EntityType().FullName());
                }
            }

            // The type of collection navigation property should have key(s) defined.
            foreach (IEdmStructuredType structuredType in model.SchemaElementsAcrossModels().OfType <IEdmStructuredType>())
            {
                foreach (var navigationProperty in structuredType.DeclaredNavigationProperties())
                {
                    if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
                    {
                        IEdmEntityType entityType = navigationProperty.ToEntityType();
                        if (!entityType.Key().Any())
                        {
                            throw Error.InvalidOperation(SRResources.CollectionNavigationPropertyEntityTypeDoesntHaveKeyDefined, entityType.FullTypeName(), navigationProperty.Name, structuredType.FullTypeName());
                        }
                    }
                }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as positional values. E.g. EntitySet('key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="positionalValues">The list of positional values.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable <KeyValuePair <string, object> > ResolveKeys(IEdmEntityType type, IList <string> positionalValues, Func <IEdmTypeReference, string, object> convertFunc)
        {
            var keyProperties = type.Key().ToList();

            // Throw an error if key size from url doesn't match that from model.
            // Other derived ODataUriResolver intended for alternative key resolution, such as the built in AlternateKeysODataUriResolver,
            // should override this ResolveKeys method.
            if (keyProperties.Count != positionalValues.Count)
            {
                throw ExceptionUtil.CreateBadRequestError(Strings.BadRequest_KeyCountMismatch(type.FullName()));
            }

            var keyPairList = new List <KeyValuePair <string, object> >(positionalValues.Count);

            for (int i = 0; i < keyProperties.Count; i++)
            {
                string       valueText      = positionalValues[i];
                IEdmProperty keyProperty    = keyProperties[i];
                object       convertedValue = convertFunc(keyProperty.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                keyPairList.Add(new KeyValuePair <string, object>(keyProperty.Name, convertedValue));
            }

            return(keyPairList);
        }
Ejemplo n.º 11
0
        public static string GetEntityKeyValue(ResourceContext resourceContext)
        {
            Contract.Assert(resourceContext != null);
            Contract.Assert(resourceContext.StructuredType != null);
            Contract.Assert(resourceContext.EdmObject != null);

            IEdmEntityType entityType = resourceContext.StructuredType as IEdmEntityType;

            if (entityType == null)
            {
                return(String.Empty);
            }

            IEnumerable <IEdmProperty> keys = entityType.Key();

            if (keys.Count() == 1)
            {
                return(GetUriRepresentationForKeyValue(keys.First(), resourceContext));
            }
            else
            {
                IEnumerable <string> keyValues =
                    keys.Select(key => String.Format(
                                    CultureInfo.InvariantCulture, "{0}={1}", key.Name, GetUriRepresentationForKeyValue(key, resourceContext)));
                return(String.Join(",", keyValues));
            }
        }
        /// <summary>
        /// Create the collection of <see cref="OpenApiLink"/> object.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="entityType">The Entity type.</param>
        /// <param name ="sourceElementName">The name of the source of the <see cref="IEdmEntityType" />.</param>
        /// <returns>The created dictionary of <see cref="OpenApiLink"/> object.</returns>
        public static IDictionary <string, OpenApiLink> CreateLinks(this ODataContext context, IEdmEntityType entityType, string sourceElementName)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(entityType, nameof(entityType));
            Utils.CheckArgumentNullOrEmpty(sourceElementName, nameof(sourceElementName));

            IDictionary <string, OpenApiLink> links = new Dictionary <string, OpenApiLink>();

            foreach (IEdmNavigationProperty np in entityType.DeclaredNavigationProperties())
            {
                OpenApiLink link = new OpenApiLink
                {
                    OperationId = sourceElementName + "." + entityType.Name + ".Get" + Utils.UpperFirstChar(entityType.Name),
                    Parameters  = new Dictionary <string, RuntimeExpressionAnyWrapper>()
                };

                foreach (IEdmStructuralProperty key in entityType.Key())
                {
                    link.Parameters[key.Name] = new RuntimeExpressionAnyWrapper
                    {
                        Any = new OpenApiString("$request.path." + key.Name)
                    };
                }

                links[np.Name] = link;
            }

            return(links);
        }
Ejemplo n.º 13
0
        // Convert the objects of keys in ODL path to string literals.
        private static string ConvertKeysToString(
            IEnumerable <KeyValuePair <string, object> > keys, IEdmType edmType,
            bool enableUriTemplateParsing)
        {
            Contract.Assert(keys != null);

            IEdmEntityType entityType = edmType as IEdmEntityType;

            Contract.Assert(entityType != null);

            if (keys.Count() < 2)
            {
                var  keyValue      = keys.First();
                bool isDeclaredKey = entityType.Key().Any(k => k.Name == keyValue.Key);

                if (isDeclaredKey)
                {
                    return(String.Join(
                               ",",
                               keys.Select(keyValuePair =>
                                           TranslateKeySegmentValue(keyValuePair.Value, enableUriTemplateParsing)).ToArray()));
                }
            }

            return(String.Join(
                       ",",
                       keys.Select(keyValuePair =>
                                   (keyValuePair.Key +
                                    "=" +
                                    TranslateKeySegmentValue(keyValuePair.Value, enableUriTemplateParsing))).ToArray()));
        }
        private static IOpenApiAny CreateStructuredTypePropertiesExample(ODataContext context, IEdmStructuredType structuredType)
        {
            OpenApiObject example = new OpenApiObject();

            IEdmEntityType entityType = structuredType as IEdmEntityType;

            // properties
            foreach (var property in structuredType.Properties())
            {
                // IOpenApiAny item;
                IEdmTypeReference propertyType = property.Type;

                IOpenApiAny item = GetTypeNameForExample(context, propertyType);

                EdmTypeKind typeKind = propertyType.TypeKind();
                if (typeKind == EdmTypeKind.Primitive && item is OpenApiString)
                {
                    OpenApiString stringAny = item as OpenApiString;
                    string        value     = stringAny.Value;
                    if (entityType != null && entityType.Key().Any(k => k.Name == property.Name))
                    {
                        value += " (identifier)";
                    }
                    if (propertyType.IsDateTimeOffset() || propertyType.IsDate() || propertyType.IsTimeOfDay())
                    {
                        value += " (timestamp)";
                    }
                    item = new OpenApiString(value);
                }

                example.Add(property.Name, item);
            }

            return(example);
        }
Ejemplo n.º 15
0
        private static string GenerateDefaultOrderBy(ODataQueryContext context)
        {
            Contract.Assert(context != null && context.EntitySet != null);

            IEdmEntityType entityType = context.EntitySet.ElementType;

            // choose the keys alphabetically. This would return a stable sort.
            string sortOrder = String.Join(",", entityType
                                           .Key()
                                           .OrderBy(property => property.Name)
                                           .Select(property => property.Name));

            if (String.IsNullOrEmpty(sortOrder))
            {
                // If there are no keys, choose the primitive properties alphabetically. This
                // might not result in a stable sort especially if there are duplicates and is only
                // a best effort solution.
                sortOrder = String.Join(",", entityType
                                        .StructuralProperties()
                                        .Where(property => property.Type.IsPrimitive())
                                        .OrderBy(property => property.Name)
                                        .Select(property => property.Name));
            }

            return(sortOrder);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Returns the list of properties that should be used for generating the skiptoken value.
        /// </summary>
        /// <param name="lastMember">The last record that will be returned in the response.</param>
        /// <param name="model">IEdmModel</param>
        /// <param name="orderByNodes">OrderBy nodes in the original request.</param>
        /// <returns>List of properties that should be used for generating the skiptoken value.</returns>
        private static IEnumerable <IEdmProperty> GetPropertiesForSkipToken(object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes)
        {
            IEdmType       edmType = GetTypeFromObject(lastMember, model);
            IEdmEntityType entity  = edmType as IEdmEntityType;

            if (entity == null)
            {
                return(null);
            }

            IEnumerable <IEdmProperty> key = entity.Key();

            if (orderByNodes != null)
            {
                if (orderByNodes.OfType <OrderByOpenPropertyNode>().Any())
                {
                    //SkipToken will not support ordering on dynamic properties
                    return(null);
                }

                IList <IEdmProperty> orderByProps = orderByNodes.OfType <OrderByPropertyNode>().Select(p => p.Property).AsList();
                foreach (IEdmProperty subKey in key)
                {
                    if (!orderByProps.Contains(subKey))
                    {
                        orderByProps.Add(subKey);
                    }
                }

                return(orderByProps.AsEnumerable());
            }

            return(key);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Test whether the action has the key parameters defined.
        /// </summary>
        /// <param name="action">The action model.</param>
        /// <param name="entityType">The Edm entity type.</param>
        /// <param name="keyPrefix">The key prefix for the action parameter.</param>
        /// <returns>True/false.</returns>
        public static bool HasODataKeyParameter(this ActionModel action, IEdmEntityType entityType, string keyPrefix = "key")
        {
            if (action == null)
            {
                throw Error.ArgumentNull(nameof(action));
            }

            if (entityType == null)
            {
                throw Error.ArgumentNull(nameof(entityType));
            }

            // TODO: shall we make sure the type is matching?
            var keys = entityType.Key().ToArray();

            if (keys.Length == 1)
            {
                // one key
                return(action.Parameters.Any(p => p.ParameterInfo.Name == keyPrefix));
            }
            else
            {
                // multipe keys
                foreach (var key in keys)
                {
                    string keyName = $"{keyPrefix}{key.Name}";
                    if (!action.Parameters.Any(p => p.ParameterInfo.Name == keyName))
                    {
                        return(false);
                    }
                }

                return(true);
            }
        }
        /// <summary>
        /// Create the collection of <see cref="OpenApiLink"/> object.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="entitySet">The Entity Set.</param>
        /// <returns>The created dictionary of <see cref="OpenApiLink"/> object.</returns>
        public static IDictionary <string, OpenApiLink> CreateLinks(this ODataContext context, IEdmEntitySet entitySet)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(entitySet, nameof(entitySet));

            IDictionary <string, OpenApiLink> links = new Dictionary <string, OpenApiLink>();
            IEdmEntityType entityType = entitySet.EntityType();

            foreach (var np in entityType.DeclaredNavigationProperties())
            {
                OpenApiLink link     = new OpenApiLink();
                string      typeName = entitySet.EntityType().Name;
                link.OperationId = entitySet.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName);
                link.Parameters  = new Dictionary <string, RuntimeExpressionAnyWrapper>();
                foreach (var key in entityType.Key())
                {
                    link.Parameters[key.Name] = new RuntimeExpressionAnyWrapper
                    {
                        Any = new OpenApiString("$request.path." + key.Name)
                    };
                }

                links[np.Name] = link;
            }

            return(links);
        }
Ejemplo n.º 19
0
        public static string TranslateKeyValueToString(this KeySegment segment)
        {
            Contract.Assert(segment != null);

            IEdmEntityType entityType = segment.EdmType as IEdmEntityType;

            Contract.Assert(entityType != null);

            var keys = segment.Keys.ToList();

            if (keys.Count < 2)
            {
                var  keyValue      = keys.First();
                bool isDeclaredKey = entityType.Key().Any(k => k.Name == keyValue.Key);

                // alternate keys are always using the "key=value"
                if (isDeclaredKey)
                {
                    return(String.Join(
                               ",",
                               keys.Select(keyValuePair =>
                                           TranslateKeySegmentValue(keyValuePair.Value)).ToArray()));
                }
            }

            return(String.Join(
                       ",",
                       keys.Select(keyValuePair =>
                                   (keyValuePair.Key +
                                    "=" +
                                    TranslateKeySegmentValue(keyValuePair.Value))).ToArray()));
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Parses the key properties based on the segment's target type, then creates a new segment for the key.
        /// </summary>
        /// <param name="segment">The segment to apply the key to.</param>
        /// <param name="key">The key to apply.</param>
        /// <returns>The newly created key segment.</returns>
        private static IPathSegment CreateKeySegment(IPathSegment segment, KeyInstance key)
        {
            Debug.Assert(segment != null, "segment != null");
            Debug.Assert(key != null && !key.IsEmpty, "key != null && !key.IsEmpty");
            Debug.Assert(segment.SingleResult == false, "segment.SingleResult == false");

            IEdmEntityType targetEntityType = null;

            WebUtil.CheckSyntaxValid(segment.TargetEdmType != null && segment.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType));
            Debug.Assert(targetEntityType != null, "targetEntityType != null");

            // Make sure the keys specified in the uri matches with the number of keys in the metadata
            var keyProperties = targetEntityType.Key().ToList();

            if (keyProperties.Count != key.ValueCount)
            {
                throw ExceptionUtil.CreateBadRequestError(ErrorStrings.BadRequest_KeyCountMismatch(targetEntityType.FullName()));
            }

            if (!key.AreValuesNamed && key.ValueCount > 1)
            {
                throw ExceptionUtil.CreateBadRequestError(ErrorStrings.RequestUriProcessor_KeysMustBeNamed);
            }

            WebUtil.CheckSyntaxValid(key.TryConvertValues(keyProperties));

            return(new PathSegment(segment)
            {
                Key = key,
                SingleResult = true,
            });
        }
        /// <summary>
        /// Get key value pair array for specific odata resource using specific entity type
        /// </summary>
        /// <param name="resource">The resource instance.</param>
        /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the resource</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair <string, object>[] GetKeyProperties(
            ODataResourceBase resource,
            ODataResourceSerializationInfo serializationInfo,
            IEdmEntityType actualEntityType)
        {
            KeyValuePair <string, object>[] keyProperties = null;
            string actualEntityTypeName = null;

            if (serializationInfo != null)
            {
                if (String.IsNullOrEmpty(resource.TypeName))
                {
                    throw new ODataException(Strings.ODataResourceTypeContext_ODataResourceTypeNameMissing);
                }

                actualEntityTypeName = resource.TypeName;
                keyProperties        = ODataResourceMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(resource, ODataPropertyKind.Key, actualEntityTypeName);
            }
            else
            {
                keyProperties = GetPropertyValues(actualEntityType.Key(), resource, actualEntityType, /*isKeyProperty*/ true, /*isRequired*/ true).ToArray();
            }

            ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName);
            return(keyProperties);
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Create <see cref="KeySegmentTemplate"/> based on the given entity type and navigation source.
        /// </summary>
        /// <param name="entityType">The given entity type.</param>
        /// <param name="navigationSource">The given navigation source.</param>
        /// <param name="keyPrefix">The prefix used before key template.</param>
        /// <returns>The built <see cref="KeySegmentTemplate"/>.</returns>
        internal static KeySegmentTemplate CreateKeySegment(IEdmEntityType entityType, IEdmNavigationSource navigationSource, string keyPrefix = "key")
        {
            if (entityType == null)
            {
                throw Error.ArgumentNull(nameof(entityType));
            }

            IDictionary <string, string> keyTemplates = new Dictionary <string, string>();
            var keys = entityType.Key().ToArray();

            if (keys.Length == 1)
            {
                // Id={key}
                keyTemplates[keys[0].Name] = $"{{{keyPrefix}}}";
            }
            else
            {
                // Id1={keyId1},Id2={keyId2}
                foreach (var key in keys)
                {
                    keyTemplates[key.Name] = $"{{{keyPrefix}{key.Name}}}";
                }
            }

            return(new KeySegmentTemplate(keyTemplates, entityType, navigationSource));
        }
        /// <summary>
        /// Get key value pair array for specifc odata resource using specifc entity type
        /// </summary>
        /// <param name="resource">The resource instance.</param>
        /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the resource</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair <string, object>[] GetKeyProperties(
            ODataResource resource,
            ODataResourceSerializationInfo serializationInfo,
            IEdmEntityType actualEntityType)
        {
            KeyValuePair <string, object>[] keyProperties = null;
            string actualEntityTypeName = null;

            if (serializationInfo != null)
            {
                if (String.IsNullOrEmpty(resource.TypeName))
                {
                    throw new ODataException(Strings.ODataResourceTypeContext_ODataResourceTypeNameMissing);
                }

                actualEntityTypeName = resource.TypeName;
                keyProperties        = ODataResourceMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(resource, ODataPropertyKind.Key, actualEntityTypeName);
            }
            else
            {
                actualEntityTypeName = actualEntityType.FullName();

                IEnumerable <IEdmStructuralProperty> edmKeyProperties = actualEntityType.Key();
                if (edmKeyProperties != null)
                {
                    keyProperties = edmKeyProperties.Select(p => new KeyValuePair <string, object>(p.Name, GetPrimitiveOrEnumPropertyValue(resource, p.Name, actualEntityTypeName, /*isKeyProperty*/ false))).ToArray();
                }
            }

            ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName);
            return(keyProperties);
        }
Ejemplo n.º 24
0
        private static ISet <IEdmStructuralProperty> GetPropertiesToIncludeInQuery(
            SelectExpandClause selectExpandClause, IEdmEntityType entityType, out ISet <IEdmStructuralProperty> autoSelectedProperties)
        {
            autoSelectedProperties = new HashSet <IEdmStructuralProperty>();
            HashSet <IEdmStructuralProperty> propertiesToInclude = new HashSet <IEdmStructuralProperty>();

            IEnumerable <SelectItem> selectedItems = selectExpandClause.SelectedItems;

            if (!IsSelectAll(selectExpandClause))
            {
                // only select requested properties and keys.
                foreach (PathSelectItem pathSelectItem in selectedItems.OfType <PathSelectItem>())
                {
                    SelectExpandNode.ValidatePathIsSupported(pathSelectItem.SelectedPath);
                    PropertySegment structuralPropertySegment = pathSelectItem.SelectedPath.LastSegment as PropertySegment;
                    if (structuralPropertySegment != null)
                    {
                        propertiesToInclude.Add(structuralPropertySegment.Property);
                    }
                }

                // add keys
                foreach (IEdmStructuralProperty keyProperty in entityType.Key())
                {
                    if (!propertiesToInclude.Contains(keyProperty))
                    {
                        autoSelectedProperties.Add(keyProperty);
                    }
                }
            }

            return(propertiesToInclude);
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Get key value pair array for specific odata resource using specific entity type
        /// </summary>
        /// <param name="resource">The resource instance.</param>
        /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the resource</param>
        /// <param name="requiresId">Whether key properties are required to be returned</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair <string, object>[] GetKeyProperties(
            ODataResourceBase resource,
            ODataResourceSerializationInfo serializationInfo,
            IEdmEntityType actualEntityType,
            bool requiresId)
        {
            Debug.Assert(resource != null, "GetKeyProperties called for a null resource.");

            KeyValuePair <string, object>[] keyProperties = null;
            string actualEntityTypeName = string.IsNullOrEmpty(resource.TypeName) ? actualEntityType?.FullName() : resource.TypeName;

            // if we have serializationInfo, try that first
            if (serializationInfo != null)
            {
                keyProperties = ODataResourceMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(resource, ODataPropertyKind.Key, actualEntityTypeName);
            }

            // if we didn't get any keys from serializationInfo, try using entity type
            if ((keyProperties == null || keyProperties.Length == 0) && actualEntityType != null)
            {
                keyProperties = GetPropertyValues(actualEntityType.Key(), resource, actualEntityType, requiresId).ToArray();
            }

            if (!ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName, requiresId))
            {
                return(Enumerable.Empty <KeyValuePair <string, object> >().ToArray());
            }

            return(keyProperties);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Compares the properties (key, structural, navigation) of an EntityType element to those in the Edm model.
        /// </summary>
        /// <param name="typeElement">The EntityType element to compare to the model.</param>
        /// <param name="entityType">The corresponding EdmEntityType from the model.</param>
        /// <param name="typeIndex">All entity types from the model, indexed by qualified name.</param>
        private static void CompareEntityTypeProperties(XElement typeElement, IEdmEntityType entityType, IDictionary <string, XElement> typeIndex)
        {
            string fullTypeName = entityType.FullName();

            CompareBaseType(typeElement, entityType);

            Func <XElement, IEnumerable <string> > getKeyPropertyNames =
                (element) =>
            {
                var keyElement = element.EdmElements("Key").SingleOrDefault();
                return(keyElement == null?Enumerable.Empty <string>() : keyElement.EdmElements("PropertyRef").Select(e => e.GetAttributeValue("Name")));
            };

            // Collect all key properties from the type hierachy and compare
            var keyPropertyNames = RecurseBaseTypes(typeElement, typeIndex, getKeyPropertyNames).ToArray();

            var keyPropertiesOnModel = entityType.Key();

            ExceptionUtilities.Assert(keyPropertyNames.Count() == keyPropertiesOnModel.Count(), "Unexpected number of key properties on type " + fullTypeName);

            var missingKeyProperties = keyPropertyNames.Except(keyPropertiesOnModel.Select(p => p.Name)).ToArray();

            ExceptionUtilities.Assert(!missingKeyProperties.Any(), "Failed to find the key properties " + string.Join(",", missingKeyProperties) + " on type " + fullTypeName);

            // Collect all structural properties from the type hierachy and compare
            var propertyElements = RecurseBaseTypes(typeElement, typeIndex, (e) => e.EdmElements("Property"));

            CompareStructuralProperties(propertyElements, entityType);

            // Collect all navigation properties from the type hierachy and compare
            var navigationPropertyElements = RecurseBaseTypes(typeElement, typeIndex, (e) => e.EdmElements("NavigationProperty"));

            CompareNavigationProperties(navigationPropertyElements, entityType);
        }
Ejemplo n.º 27
0
        private static KeySegment BuildKeySegment(IEdmEntityType entityType, IEdmEntitySetBase entitySet, object target)
        {
            if (entityType == null)
            {
                throw new ArgumentNullException("entityType");
            }

            if (entitySet == null)
            {
                throw new ArgumentNullException("entitySet");
            }

            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            KeySegment keySegment = new KeySegment(
                entityType.Key().Select(
                    (key) =>
            {
                var keyValue = target.GetType().GetProperty(key.Name).GetValue(target, null);
                return(new KeyValuePair <string, object>(key.Name, keyValue));
            }),
                entityType,
                entitySet);

            return(keySegment);
        }
        private static string GetKeyInfos(int keyCount, string keyName, IEdmEntityType entityType, string keyPrefix, out IEdmTypeReference keyType)
        {
            Contract.Assert(keyName != null);
            Contract.Assert(entityType != null);

            string newKeyName;
            IEdmStructuralProperty keyProperty;

            if (String.IsNullOrEmpty(keyName))
            {
                Contract.Assert(keyCount == 1);
                keyProperty = entityType.Key().First();
                newKeyName = keyPrefix;
            }
            else
            {
                bool alternateKey = false;
                keyProperty = entityType.Key().FirstOrDefault(k => k.Name == keyName);
                if (keyProperty == null)
                {
                    // If it's alternate key.
                    keyProperty =
                        entityType.Properties().OfType<IEdmStructuralProperty>().FirstOrDefault(p => p.Name == keyName);
                    alternateKey = true;
                }
                Contract.Assert(keyProperty != null);

                // if there's only one key, just use the given prefix name, for example: "key, relatedKey"  
                // otherwise, to append the key name after the given prefix name.  
                // so for multiple keys, the parameter name is "keyId1, keyId2..."  
                // for navigation property, the parameter name is "relatedKeyId1, relatedKeyId2 ..."  
                // for alternate key, to append the alternate key name after the given prefix name.  
                if (alternateKey || keyCount > 1)
                {
                    newKeyName = keyPrefix + keyName;
                }
                else
                {
                    newKeyName = keyPrefix;
                }
            }

            keyType = keyProperty.Type;
            return newKeyName;
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Parses the key properties based on the segment's target type, then creates a new segment for the key.
        /// </summary>
        /// <param name="segment">The segment to apply the key to.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="key">The key to apply.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>The newly created key segment.</returns>
        private static KeySegment CreateKeySegment(ODataPathSegment segment, KeySegment previousKeySegment, SegmentArgumentParser key, ODataUriResolver resolver)
        {
            Debug.Assert(segment != null, "segment != null");
            Debug.Assert(key != null && !key.IsEmpty, "key != null && !key.IsEmpty");
            Debug.Assert(segment.SingleResult == false, "segment.SingleResult == false");

            IEdmEntityType targetEntityType = null;

            if (!(segment.TargetEdmType != null && segment.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType)))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            Debug.Assert(targetEntityType != null, "targetEntityType != null");

            // Make sure the keys specified in the uri matches with the number of keys in the metadata
            var keyProperties = targetEntityType.Key().ToList();

            if (keyProperties.Count != key.ValueCount)
            {
                NavigationPropertySegment currentNavPropSegment = segment as NavigationPropertySegment;
                if (currentNavPropSegment != null)
                {
                    key = KeyFinder.FindAndUseKeysFromRelatedSegment(key, keyProperties, currentNavPropSegment.NavigationProperty, previousKeySegment);
                }

                // if we still didn't find any keys, then throw an error.
                if (keyProperties.Count != key.ValueCount && resolver.GetType() == typeof(ODataUriResolver))
                {
                    throw ExceptionUtil.CreateBadRequestError(ErrorStrings.BadRequest_KeyCountMismatch(targetEntityType.FullName()));
                }
            }

            if (!key.AreValuesNamed && key.ValueCount > 1 && resolver.GetType() == typeof(ODataUriResolver))
            {
                throw ExceptionUtil.CreateBadRequestError(ErrorStrings.RequestUriProcessor_KeysMustBeNamed);
            }

            IEnumerable <KeyValuePair <string, object> > keyPairs;

            if (!key.TryConvertValues(targetEntityType, out keyPairs, resolver))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            IEdmEntityType entityType;
            bool           isEntity = segment.TargetEdmType.IsEntityOrEntityCollectionType(out entityType);

            Debug.Assert(isEntity, "Key target type should be an entity type.");

            var keySegment = new KeySegment(keyPairs, entityType, segment.TargetEdmNavigationSource);

            keySegment.CopyValuesFrom(segment);
            keySegment.SingleResult = true;

            return(keySegment);
        }
Ejemplo n.º 30
0
        /// <summary>Tries to convert values to the keys of the specified type.</summary>
        /// <param name="targetEntityType">The specified type.</param>
        /// <param name="keyPairs">The converted key-value pairs.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>true if all values were converted; false otherwise.</returns>
        public bool TryConvertValues(IEdmEntityType targetEntityType, out IEnumerable <KeyValuePair <string, object> > keyPairs, ODataUriResolver resolver)
        {
            Debug.Assert(!this.IsEmpty, "!this.IsEmpty -- caller should check");
            Debug.Assert(targetEntityType.Key().Count() == this.ValueCount || resolver.GetType() != typeof(ODataUriResolver), "type.KeyProperties.Count == this.ValueCount -- will change with containment");

            if (this.NamedValues != null)
            {
                keyPairs = resolver.ResolveKeys(targetEntityType, this.NamedValues, this.ConvertValueWrapper);
            }
            else
            {
                Debug.Assert(this.positionalValues != null, "positionalValues != null -- otherwise this is Empty");
                Debug.Assert(this.PositionalValues.Count == targetEntityType.Key().Count() || resolver.GetType() != typeof(ODataUriResolver), "Count of positional values does not match.");
                keyPairs = resolver.ResolveKeys(targetEntityType, this.PositionalValues, this.ConvertValueWrapper);
            }

            return(true);
        }
Ejemplo n.º 31
0
        private void CompareEntityType(IEdmEntityType expectedEntityType, IEdmEntityType actualEntityType)
        {
            this.SatisfiesEquals(expectedEntityType.FullName(), actualEntityType.FullName(), "EntityType name does not match.");
            this.SatisfiesEquals(expectedEntityType.IsAbstract, actualEntityType.IsAbstract, "IsAbstract does not match for EntityType '{0}'.", expectedEntityType.FullName());

            string expectedBaseTypeName = expectedEntityType.BaseType != null ? ((IEdmSchemaElement)expectedEntityType.BaseType).FullName() : null;
            string actualBaseTypeName = actualEntityType.BaseType != null ? ((IEdmSchemaElement)actualEntityType.BaseType).FullName() : null;

            this.SatisfiesEquals(expectedBaseTypeName, actualBaseTypeName, "BaseType does not match for EntityType '{0}'.", expectedEntityType.FullName());
            this.CompareProperties(expectedEntityType.StructuralProperties().Cast<IEdmProperty>(), actualEntityType.StructuralProperties().Cast<IEdmProperty>());
            this.CompareProperties(expectedEntityType.Key().OfType<IEdmProperty>(), actualEntityType.Key().OfType<IEdmProperty>());
            this.CompareNavigationProperty(expectedEntityType.Properties().OfType<IEdmNavigationProperty>(), actualEntityType.Properties().OfType<IEdmNavigationProperty>());

            this.CompareTermAnnotations(expectedEntityType, actualEntityType);
        }
Ejemplo n.º 32
0
        private EntityType ConvertToTaupoEntityType(IEdmEntityType edmEntityType)
        {
            var taupoEntityType = new EntityType(edmEntityType.Namespace, edmEntityType.Name)
            {
                IsAbstract = edmEntityType.IsAbstract,
                IsOpen = edmEntityType.IsOpen,
            };

            if (edmEntityType.BaseType != null)
            {
                taupoEntityType.BaseType = new EntityTypeReference(edmEntityType.BaseEntityType().Namespace, edmEntityType.BaseEntityType().Name);
            }

            foreach (var edmProperty in edmEntityType.DeclaredStructuralProperties())
            {
                var taupoProperty = this.ConvertToTaupoProperty(edmProperty);
                taupoProperty.IsPrimaryKey = edmEntityType.Key().Contains(edmProperty);
                taupoEntityType.Add(taupoProperty);
            }

            this.ConvertAnnotationsIntoTaupo(edmEntityType, taupoEntityType);
            return taupoEntityType;
        }
Ejemplo n.º 33
0
        private static ISet<IEdmStructuralProperty> GetPropertiesToIncludeInQuery(
            SelectExpandClause selectExpandClause, IEdmEntityType entityType, out ISet<IEdmStructuralProperty> autoSelectedProperties)
        {
            autoSelectedProperties = new HashSet<IEdmStructuralProperty>();
            HashSet<IEdmStructuralProperty> propertiesToInclude = new HashSet<IEdmStructuralProperty>();

            PartialSelection selection = selectExpandClause.Selection as PartialSelection;
            if (selection != null && !selection.SelectedItems.OfType<WildcardSelectionItem>().Any())
            {
                // only select requested properties and keys.
                foreach (PathSelectionItem pathSelectionItem in selection.SelectedItems.OfType<PathSelectionItem>())
                {
                    SelectExpandNode.ValidatePathIsSupported(pathSelectionItem.SelectedPath);
                    PropertySegment structuralPropertySegment = pathSelectionItem.SelectedPath.LastSegment as PropertySegment;
                    if (structuralPropertySegment != null)
                    {
                        propertiesToInclude.Add(structuralPropertySegment.Property);
                    }
                }

                // add keys
                foreach (IEdmStructuralProperty keyProperty in entityType.Key())
                {
                    if (!propertiesToInclude.Contains(keyProperty))
                    {
                        autoSelectedProperties.Add(keyProperty);
                    }
                }
            }

            return propertiesToInclude;
        }
Ejemplo n.º 34
0
        /// <summary>
        /// Tries to bind key values to a key lookup on a collection.
        /// </summary>
        /// <param name="collectionNode">Already bound collection node.</param>
        /// <param name="namedValues">The named value tokens to bind.</param>
        /// <param name="model">The model to be used.</param>
        /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param>
        /// <param name="keyLookupNode">The bound key lookup.</param>
        /// <returns>Returns true if binding succeeded.</returns>
        private bool TryBindToDeclaredKey(EntityCollectionNode collectionNode, IEnumerable<NamedValue> namedValues, IEdmModel model, IEdmEntityType collectionItemEntityType, out QueryNode keyLookupNode)
        {
            Dictionary<string, IEdmProperty> keys = new Dictionary<string, IEdmProperty>(StringComparer.Ordinal);
            foreach (IEdmStructuralProperty property in collectionItemEntityType.Key())
            {
                keys[property.Name] = property;
            }

            return TryBindToKeys(collectionNode, namedValues, model, collectionItemEntityType, keys, out keyLookupNode);
        }
Ejemplo n.º 35
0
        /// <summary>
        /// Get key value pair array for specifc odata entry using specifc entity type
        /// </summary>
        /// <param name="entry">The entry instance.</param>
        /// <param name="serializationInfo">The serialization info of the entry for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the entry</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair<string, object>[] GetKeyProperties(
            ODataEntry entry,
            ODataFeedAndEntrySerializationInfo serializationInfo,
            IEdmEntityType actualEntityType)
        {
            KeyValuePair<string, object>[] keyProperties = null;
            string actualEntityTypeName = null;

            if (serializationInfo != null)
            {
                if (String.IsNullOrEmpty(entry.TypeName))
                {
                    throw new ODataException(OData.Core.Strings.ODataFeedAndEntryTypeContext_ODataEntryTypeNameMissing);
                }

                actualEntityTypeName = entry.TypeName;
                keyProperties = ODataEntryMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(entry, ODataPropertyKind.Key, actualEntityTypeName);
            }
            else
            {
                actualEntityTypeName = actualEntityType.FullName();

                IEnumerable<IEdmStructuralProperty> edmKeyProperties = actualEntityType.Key();
                if (edmKeyProperties != null)
                {
                    keyProperties = edmKeyProperties.Select(p => new KeyValuePair<string, object>(p.Name, GetPrimitivePropertyClrValue(entry, p.Name, actualEntityTypeName, /*isKeyProperty*/false))).ToArray();
                }
            }

            ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName);
            return keyProperties;
        }
Ejemplo n.º 36
0
        /// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as name value pairs. E.g. EntitySet(ID='key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="namedValues">The dictionary of name value pairs.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable<KeyValuePair<string, object>> ResolveKeys(IEdmEntityType type, IDictionary<string, string> namedValues, Func<IEdmTypeReference, string, object> convertFunc)
        {
            var convertedPairs = new Dictionary<string, object>(StringComparer.Ordinal);
            var keyProperties = type.Key().ToList();

            foreach (IEdmStructuralProperty property in keyProperties)
            {
                string valueText;

                if (EnableCaseInsensitive)
                {
                    var list = namedValues.Keys.Where(key => string.Equals(property.Name, key, StringComparison.OrdinalIgnoreCase)).ToList();
                    if (list.Count > 1)
                    {
                        throw new ODataException(Strings.UriParserMetadata_MultipleMatchingKeysFound(property.Name));
                    }
                    else if (list.Count == 0)
                    {
                        throw ExceptionUtil.CreateSyntaxError();
                    }

                    valueText = namedValues[list.Single()];
                }
                else if (!namedValues.TryGetValue(property.Name, out valueText))
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                object convertedValue = convertFunc(property.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                convertedPairs[property.Name] = convertedValue;
            }

            return convertedPairs;
        }
Ejemplo n.º 37
0
        /// <summary>
        /// Resolve keys for certain entity set, this function would be called when key is specified as positional values. E.g. EntitySet('key')
        /// </summary>
        /// <param name="type">Type for current entityset.</param>
        /// <param name="positionalValues">The list of positional values.</param>
        /// <param name="convertFunc">The convert function to be used for value converting.</param>
        /// <returns>The resolved key list.</returns>
        public virtual IEnumerable<KeyValuePair<string, object>> ResolveKeys(IEdmEntityType type, IList<string> positionalValues, Func<IEdmTypeReference, string, object> convertFunc)
        {
            var keyProperties = type.Key().ToList();
            var keyPairList = new List<KeyValuePair<string, object>>(positionalValues.Count);

            for (int i = 0; i < keyProperties.Count; i++)
            {
                string valueText = positionalValues[i];
                IEdmProperty keyProperty = keyProperties[i];
                object convertedValue = convertFunc(keyProperty.Type, valueText);
                if (convertedValue == null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                keyPairList.Add(new KeyValuePair<string, object>(keyProperty.Name, convertedValue));
            }

            return keyPairList;
        }
Ejemplo n.º 38
0
        /// <summary>
        /// Binds key values to a key lookup on a collection.
        /// </summary>
        /// <param name="collectionNode">Already bound collection node.</param>
        /// <param name="namedValues">The named value tokens to bind.</param>
        /// <param name="model">The model to be used.</param>
        /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param>
        /// <param name="keys">Dictionary of aliases to structural property names for the key.</param>
        /// <param name="keyLookupNode">The bound key lookup.</param>
        /// <returns>Returns true if binding succeeded.</returns>
        private bool TryBindToKeys(EntityCollectionNode collectionNode, IEnumerable<NamedValue> namedValues, IEdmModel model, IEdmEntityType collectionItemEntityType, IDictionary<string, IEdmProperty> keys, out QueryNode keyLookupNode)
        {
            List<KeyPropertyValue> keyPropertyValues = new List<KeyPropertyValue>();
            HashSet<string> keyPropertyNames = new HashSet<string>(StringComparer.Ordinal);
            foreach (NamedValue namedValue in namedValues)
            {
                KeyPropertyValue keyPropertyValue;

                if (!this.TryBindKeyPropertyValue(namedValue, collectionItemEntityType, keys, out keyPropertyValue))
                {
                    keyLookupNode = null;
                    return false;
                }

                Debug.Assert(keyPropertyValue != null, "keyPropertyValue != null");
                Debug.Assert(keyPropertyValue.KeyProperty != null, "keyPropertyValue.KeyProperty != null");

                if (!keyPropertyNames.Add(keyPropertyValue.KeyProperty.Name))
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_DuplicitKeyPropertyInKeyValues(keyPropertyValue.KeyProperty.Name));
                }

                keyPropertyValues.Add(keyPropertyValue);
            }

            if (keyPropertyValues.Count == 0)
            {
                // No key values specified, for example '/Customers()', do not include the key lookup at all
                keyLookupNode = collectionNode;
                return true;
            }
            else if (keyPropertyValues.Count != collectionItemEntityType.Key().Count())
            {
                keyLookupNode = null;
                return false;
            }
            else
            {
                keyLookupNode = new KeyLookupNode(collectionNode, new ReadOnlyCollection<KeyPropertyValue>(keyPropertyValues));
                return true;
            }
        }
Ejemplo n.º 39
0
        /// <summary>
        /// Binds a key property value.
        /// </summary>
        /// <param name="namedValue">The named value to bind.</param>
        /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param>
        /// <returns>The bound key property value node.</returns>
        private KeyPropertyValue BindKeyPropertyValue(NamedValue namedValue, IEdmEntityType collectionItemEntityType)
        {
            // These are exception checks because the data comes directly from the potentially user specified tree.
            ExceptionUtils.CheckArgumentNotNull(namedValue, "namedValue");
            ExceptionUtils.CheckArgumentNotNull(namedValue.Value, "namedValue.Value");
            Debug.Assert(collectionItemEntityType != null, "collectionItemType != null");

            IEdmProperty keyProperty = null;
            if (namedValue.Name == null)
            {
                foreach (IEdmProperty p in collectionItemEntityType.Key())
                {
                    if (keyProperty == null)
                    {
                        keyProperty = p;
                    }
                    else
                    {
                        throw new ODataException(Strings.MetadataBinder_UnnamedKeyValueOnTypeWithMultipleKeyProperties(collectionItemEntityType.ODataFullName()));
                    }
                }
            }
            else
            {
                keyProperty = collectionItemEntityType.Key().Where(k => string.CompareOrdinal(k.Name, namedValue.Name) == 0).SingleOrDefault();

                if (keyProperty == null)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyNotDeclaredOrNotKeyInKeyValue(namedValue.Name, collectionItemEntityType.ODataFullName()));
                }
            }

            IEdmTypeReference keyPropertyType = keyProperty.Type;

            SingleValueQueryNode value = (SingleValueQueryNode)this.Bind(namedValue.Value);

            // TODO: Check that the value is of primitive type
            value = ConvertToType(value, keyPropertyType);

            Debug.Assert(keyProperty != null, "keyProperty != null");
            return new KeyPropertyValue()
            {
                KeyProperty = keyProperty,
                KeyValue = value
            };
        }
Ejemplo n.º 40
0
        private static IReadOnlyDictionary<string, object> GetPathKeyValues(
            KeyValuePathSegment keySegment,
            IEdmEntityType entityType)
        {
            var result = new Dictionary<string, object>();
            var keys = entityType.Key();

            // TODO GitHubIssue#42 : Improve key parsing logic
            // this parsing implementation does not allow key values to contain commas
            // Depending on the WebAPI to make KeyValuePathSegment.Values collection public
            // (or have the parsing logic public).
            string[] values = keySegment.Value.Split(EntityKeySeparator);
            if (values.Length > 1)
            {
                foreach (string value in values)
                {
                    // Split key name and key value
                    var keyValues = value.Split(EntityKeyNameValueSeparator);
                    if (keyValues.Length != 2)
                    {
                        throw new InvalidOperationException(Resources.IncorrectKeyFormat);
                    }

                    // Validate the key name
                    if (!keys.Select(k => k.Name).Contains(keyValues[0]))
                    {
                        throw new InvalidOperationException(
                            string.Format(
                            CultureInfo.InvariantCulture,
                            Resources.KeyNotValidForEntityType,
                            keyValues[0],
                            entityType.Name));
                    }

                    result.Add(keyValues[0], ODataUriUtils.ConvertFromUriLiteral(keyValues[1], ODataVersion.V4));
                }
            }
            else
            {
                // We just have the single key value
                // Validate it has exactly one key
                if (keys.Count() > 1)
                {
                    throw new InvalidOperationException(Resources.MultiKeyValuesExpected);
                }

                var keyName = keys.First().Name;
                result.Add(keyName, ODataUriUtils.ConvertFromUriLiteral(keySegment.Value, ODataVersion.V4));
            }

            return result;
        }
        /// <summary>
        /// Creates the key segment to use in the ID/EDitLink fields of an entry.
        /// </summary>
        /// <param name="entityInstance">The instance to get the key values from</param>
        /// <param name="entityType">The entity type of the instance</param>
        /// <param name="targetVersion">The OData version this segment is targeting.</param>
        /// <returns>A Key segment that contains a literal encoded string key-value pairs for property names and their values</returns>
        private static string BuildKeyString(object entityInstance, IEdmEntityType entityType, ODataVersion targetVersion)
        {
            if (entityType.DeclaredKey != null && entityType.DeclaredKey.Count() == 1)
            {
                var keyMember = entityType.Key().Single();
                PropertyInfo property = entityInstance.GetType().GetProperty(keyMember.Name);
                return ODataUriUtils.ConvertToUriLiteral(property.GetValue(entityInstance, null), targetVersion, DataSourceManager.GetCurrentDataSource().Model);
            }
            else
            {
                var keyStringFragments = new List<string>();
                foreach (var keyMember in entityType.Key())
                {
                    PropertyInfo property = entityInstance.GetType().GetProperty(keyMember.Name);
                    keyStringFragments.Add(String.Format("{0}={1}", keyMember.Name, ODataUriUtils.ConvertToUriLiteral(property.GetValue(entityInstance, null), targetVersion, DataSourceManager.GetCurrentDataSource().Model)));
                }

                return String.Join(",", keyStringFragments);
            }
        }
Ejemplo n.º 42
0
        private static KeySegment BuildKeySegment(IEdmEntityType entityType, IEdmEntitySetBase entitySet, object target)
        {
            if (entityType == null)
            {
                throw new ArgumentNullException("entityType");
            }

            if (entitySet == null)
            {
                throw new ArgumentNullException("entitySet");
            }

            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            KeySegment keySegment = new KeySegment(
                entityType.Key().Select(
                    (key) =>
                    {
                        var keyValue = target.GetType().GetProperty(key.Name).GetValue(target, null);
                        return new KeyValuePair<string, object>(key.Name, keyValue);
                    }),
                entityType,
                entitySet);

            return keySegment;
        }
Ejemplo n.º 43
0
        internal void WriteEntityType(IEdmEntityType entityType, Dictionary<IEdmStructuredType, List<IEdmOperation>> boundOperationsMap)
        {
            var entityTypeName = entityType.Name;
            entityTypeName = Context.EnableNamingAlias ? Customization.CustomizeNaming(entityTypeName) : entityTypeName;
            WriteSummaryCommentForStructuredType(entityTypeName + SingleSuffix);
            WriteStructurdTypeDeclaration(entityType,
                ClassInheritMarker + string.Format(DataServiceQuerySingleStructureTemplate, GetFixedName(entityTypeName)),
                SingleSuffix);
            var singleTypeName = (Context.EnableNamingAlias ?
                Customization.CustomizeNaming(entityType.Name) : entityType.Name) + SingleSuffix;
            WriteConstructorForSingleType(GetFixedName(singleTypeName), string.Format(DataServiceQuerySingleStructureTemplate, GetFixedName(entityTypeName)));
            var current = entityType;
            while (current != null)
            {
                WritePropertiesForSingleType(current.DeclaredProperties);
                current = (IEdmEntityType)current.BaseType;
            }

            WriteClassEndForStructuredType();

            WriteSummaryCommentForStructuredType(Context.EnableNamingAlias ? Customization.CustomizeNaming(entityType.Name) : entityType.Name);

            if (entityType.Key().Any())
            {
                var keyProperties = entityType.Key().Select(k => k.Name);
                WriteKeyPropertiesCommentAndAttribute(
                    Context.EnableNamingAlias ? keyProperties.Select(k => Customization.CustomizeNaming(k)) : keyProperties,
                    string.Join("\", \"", keyProperties));
            }
            else
            {
                WriteEntityTypeAttribute();
            }

            if (Context.UseDataServiceCollection)
            {
                List<IEdmNavigationSource> navigationSourceList;
                if (Context.ElementTypeToNavigationSourceMap.TryGetValue(entityType, out navigationSourceList))
                {
                    if (navigationSourceList.Count == 1)
                    {
                        WriteEntitySetAttribute(navigationSourceList[0].Name);
                    }
                }
            }

            if (entityType.HasStream)
            {
                WriteEntityHasStreamAttribute();
            }

            WriteStructurdTypeDeclaration(entityType, BaseEntityType);
            SetPropertyIdentifierMappingsIfNameConflicts(entityType.Name, entityType);
            WriteTypeStaticCreateMethod(entityType.Name, entityType);
            WritePropertiesForStructuredType(entityType.DeclaredProperties);

            if (entityType.BaseType == null && Context.UseDataServiceCollection)
            {
                WriteINotifyPropertyChangedImplementation();
            }

            WriteBoundOperations(entityType, boundOperationsMap);

            WriteClassEndForStructuredType();
        }