/// <summary> /// Gets the property info for the EDM property declared on this type. /// </summary> /// <param name="structuredType">The structured type to get the property on.</param> /// <param name="property">Property instance to get the property info for.</param> /// <param name="model">The model containing annotations.</param> /// <returns>Returns the PropertyInfo object for the specified EDM property.</returns> internal PropertyInfo GetPropertyInfo(IEdmStructuredType structuredType, IEdmProperty property, IEdmModel model) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(structuredType != null, "structuredType != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(model != null, "model != null"); Debug.Assert(property.GetCanReflectOnInstanceTypeProperty(model), "property.CanReflectOnInstanceTypeProperty()"); #if DEBUG Debug.Assert(structuredType.ContainsProperty(property), "The structuredType does not define the specified property."); #endif if (this.propertyInfosDeclaredOnThisType == null) { this.propertyInfosDeclaredOnThisType = new Dictionary<IEdmProperty, PropertyInfo>(ReferenceEqualityComparer<IEdmProperty>.Instance); } PropertyInfo propertyInfo; if (!this.propertyInfosDeclaredOnThisType.TryGetValue(property, out propertyInfo)) { BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; propertyInfo = structuredType.GetInstanceType(model).GetProperty(property.Name, bindingFlags); if (propertyInfo == null) { throw new ODataException(Strings.PropertyInfoTypeAnnotation_CannotFindProperty(structuredType.ODataFullName(), structuredType.GetInstanceType(model), property.Name)); } this.propertyInfosDeclaredOnThisType.Add(property, propertyInfo); } Debug.Assert(propertyInfo != null, "propertyInfo != null"); return propertyInfo; }
internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKind, string propertyName, object propertyValue, IEdmProperty edmProperty, ODataDeserializerContext readContext) { if (propertyKind == EdmTypeKind.Collection) { SetCollectionProperty(resource, edmProperty, propertyValue, propertyName); } else { if (!readContext.IsUntyped) { if (propertyKind == EdmTypeKind.Primitive) { propertyValue = EdmPrimitiveHelpers.ConvertPrimitiveValue(propertyValue, GetPropertyType(resource, propertyName)); } else if (propertyKind == EdmTypeKind.Enum) { propertyValue = EnumDeserializationHelpers.ConvertEnumValue(propertyValue, GetPropertyType(resource, propertyName)); } } SetProperty(resource, propertyName, propertyValue); } }
public EdmPropertyReferenceExpression(IEdmExpression baseExpression, IEdmProperty referencedProperty) { EdmUtil.CheckArgumentNull<IEdmExpression>(baseExpression, "baseExpression"); EdmUtil.CheckArgumentNull<IEdmProperty>(referencedProperty, "referencedPropert"); this.baseExpression = baseExpression; this.referencedProperty = referencedProperty; }
public static IQueryable OrderByProperty(IQueryable query, IEdmModel model, IEdmProperty property, OrderByDirection direction, Type type, bool alreadyOrdered = false) { // property aliasing string propertyName = EdmLibHelpers.GetClrPropertyName(property, model); LambdaExpression orderByLambda = GetPropertyAccessLambda(type, propertyName); return OrderBy(query, orderByLambda, direction, type, alreadyOrdered); }
public EdmPropertyValueBinding(IEdmProperty boundProperty, IEdmExpression value) { EdmUtil.CheckArgumentNull<IEdmProperty>(boundProperty, "boundProperty"); EdmUtil.CheckArgumentNull<IEdmExpression>(value, "value"); this.boundProperty = boundProperty; this.@value = value; }
/// <summary> /// Generates a bound query node representing an <see cref="IEdmProperty"/> given an already semantically bound parent node. /// </summary> /// <param name="parentNode">The semantically bound source node of this end path token</param> /// <param name="property">The <see cref="IEdmProperty"/> that will be bound to this node. Must not be primitive collection</param> /// <returns>QueryNode bound to this property.</returns> internal static QueryNode GeneratePropertyAccessQueryNode(SingleValueNode parentNode, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(parentNode, "parent"); ExceptionUtils.CheckArgumentNotNull(property, "property"); // TODO: Remove this check. // We should verify that the top level of an expression is a bool rather than arbitrarily restrict property types. // We can get here if there is a query like $filter=MyCollectionProperty eq 'foo' or something. // If it was $filter=MyCollectionProperty/any(...) then we would have gone down the 'NonRootSegment' code path instead of this one if (property.Type.IsNonEntityCollectionType()) { // if this happens to be a top level node (i.e. $filter=MyCollection), then it will fail further up the chain, so // don't need to worry about checking for that here. return new CollectionPropertyAccessNode(parentNode, property); } if (property.PropertyKind == EdmPropertyKind.Navigation) { // These are error cases in practice, but we let ourselves throw later for better context-sensitive error messages var edmNavigationProperty = (IEdmNavigationProperty)property; var singleEntityParentNode = (SingleEntityNode)parentNode; if (edmNavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { return new CollectionNavigationNode(edmNavigationProperty, singleEntityParentNode); } return new SingleNavigationNode(edmNavigationProperty, singleEntityParentNode); } return new SingleValuePropertyAccessNode(parentNode, property); }
/// <summary> /// Gets the reader behavior for null property value on the specified property. /// </summary> /// <param name="model">The model containing the annotation.</param> /// <param name="property">The property to check.</param> /// <returns>The behavior to use when reading null value for this property.</returns> public static ODataNullValueBehaviorKind NullValueReadBehaviorKind(this IEdmModel model, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(model, "model"); ExceptionUtils.CheckArgumentNotNull(property, "property"); ODataEdmPropertyAnnotation annotation = model.GetAnnotationValue<ODataEdmPropertyAnnotation>(property); return annotation == null ? ODataNullValueBehaviorKind.Default : annotation.NullValueReadBehaviorKind; }
/// <summary> /// Initializes a new instance of the <see cref="OrderByPropertyNode"/> class. /// </summary> /// <param name="property">The <see cref="IEdmProperty"/> for this node.</param> /// <param name="direction">The <see cref="OrderByDirection"/> for this node.</param> public OrderByPropertyNode(IEdmProperty property, OrderByDirection direction) : base(direction) { if (property == null) { throw Error.ArgumentNull("property"); } Property = property; }
/// <summary> /// Initializes a new instance of the <see cref="PropertyAccessPathSegment" /> class. /// </summary> /// <param name="property">The property being accessed by this segment.</param> public PropertyAccessPathSegment(IEdmProperty property) { if (property == null) { throw Error.ArgumentNull("property"); } Property = property; PropertyName = property.Name; }
/// <summary> /// Initializes a new instance of the <see cref="PropertyAccessPathSegment" /> class. /// </summary> /// <param name="previous">The previous segment in the path.</param> /// <param name="property">The property being accessed by this segment.</param> public PropertyAccessPathSegment(ODataPathSegment previous, IEdmProperty property) : base(previous) { if (property == null) { throw Error.ArgumentNull("property"); } EdmType = property.Type.Definition; Property = property; }
/// <summary> /// Adds the <paramref name="property"/> to this type. /// <see cref="IEdmProperty.DeclaringType"/> of the <paramref name="property"/> must be this type. /// </summary> /// <param name="property">The property being added.</param> public void AddProperty(IEdmProperty property) { EdmUtil.CheckArgumentNull(property, "property"); if (!Object.ReferenceEquals(this, property.DeclaringType)) { throw new InvalidOperationException(Edm.Strings.EdmModel_Validator_Semantic_DeclaringTypeMustBeCorrect(property.Name)); } this.declaredProperties.Add(property); this.propertiesDictionary.Clear(null); }
public static void SetISOCurrencyMeasuresAnnotation(this EdmModel model, IEdmProperty property, string isoCurrency) { if (model == null) throw new ArgumentNullException("model"); if (property == null) throw new ArgumentNullException("property"); var target = property; var term = ISOCurrencyTerm; var expression = new EdmStringConstant(isoCurrency); var annotation = new EdmAnnotation(target, term, expression); annotation.SetSerializationLocation(model, property.ToSerializationLocation()); model.AddVocabularyAnnotation(annotation); }
public static void SetScaleMeasuresAnnotation(this EdmModel model, IEdmProperty property, byte scale) { if (model == null) throw new ArgumentNullException("model"); if (property == null) throw new ArgumentNullException("property"); var target = property; var term = ScaleTerm; var expression = new EdmIntegerConstant(scale); var annotation = new EdmAnnotation(target, term, expression); annotation.SetSerializationLocation(model, property.ToSerializationLocation()); model.AddVocabularyAnnotation(annotation); }
public static void SetComputedAnnotation(EdmModel model, IEdmProperty target) { EdmUtil.CheckArgumentNull(model, "model"); EdmUtil.CheckArgumentNull(target, "target"); IEdmBooleanConstantExpression val = new EdmBooleanConstant(true); IEdmValueTerm term = CoreVocabularyModel.ComputedTerm; Debug.Assert(term != null, "term!=null"); EdmAnnotation annotation = new EdmAnnotation(target, term, val); annotation.SetSerializationLocation(model, EdmVocabularyAnnotationSerializationLocation.Inline); model.SetVocabularyAnnotation(annotation); }
/// <summary> /// Gets the property info for the EDM property on the specified type. /// </summary> /// <param name="typeReference">The type to get the property on.</param> /// <param name="property">Property instance to get the property info for.</param> /// <param name="model">Model containing annotations.</param> /// <returns>Returns the PropertyInfo object for the specified property.</returns> /// <remarks>The method searches this type as well as all its base types for the property.</remarks> internal static PropertyInfo GetPropertyInfo(this IEdmStructuredTypeReference typeReference, IEdmProperty property, IEdmModel model) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(typeReference != null, "typeReference != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(model != null, "model != null"); Debug.Assert(property.GetCanReflectOnInstanceTypeProperty(model), "property.CanReflectOnInstanceTypeProperty()"); #if DEBUG Debug.Assert(typeReference.ContainsProperty(property), "The typeReference does not define the specified property."); #endif IEdmStructuredType structuredType = typeReference.StructuredDefinition(); return PropertyInfoTypeAnnotation.GetPropertyInfoTypeAnnotation(structuredType, model).GetPropertyInfo(structuredType, property, model); }
internal static void SetCollectionProperty(object resource, IEdmProperty edmProperty, object value) { Contract.Assert(edmProperty != null); if (value != null) { string propertyName = edmProperty.Name; IEnumerable collection = value as IEnumerable; Contract.Assert(collection != null, "SetCollectionProperty is always passed the result of ODataFeedDeserializer or ODataCollectionDeserializer"); Type resourceType = resource.GetType(); Type propertyType = GetPropertyType(resource, propertyName); Type elementType; if (!propertyType.IsCollection(out elementType)) { string message = Error.Format(SRResources.PropertyIsNotCollection, propertyType.FullName, propertyName, resourceType.FullName); throw new SerializationException(message); } IEnumerable newCollection; if (CanSetProperty(resource, propertyName) && CollectionDeserializationHelpers.TryCreateInstance(propertyType, edmProperty.Type.AsCollection(), elementType, out newCollection)) { // settable collections collection.AddToCollection(newCollection, elementType, resourceType, propertyName, propertyType); if (propertyType.IsArray) { newCollection = CollectionDeserializationHelpers.ToArray(newCollection, elementType); } SetProperty(resource, propertyName, newCollection); } else { // get-only collections. newCollection = GetProperty(resource, propertyName) as IEnumerable; if (newCollection == null) { string message = Error.Format(SRResources.CannotAddToNullCollection, propertyName, resourceType.FullName); throw new SerializationException(message); } collection.AddToCollection(newCollection, elementType, resourceType, propertyName, propertyType); } } }
private PropertyInfo GetPropertyInfo(IEdmProperty property) { ClrPropertyInfoAnnotation clrPropertyAnnotation = _model.GetAnnotationValue<ClrPropertyInfoAnnotation>(property); if (clrPropertyAnnotation != null) { return clrPropertyAnnotation.ClrPropertyInfo; } ClrTypeAnnotation clrTypeAnnotation = _model.GetAnnotationValue<ClrTypeAnnotation>(property.DeclaringType); Contract.Assert(clrTypeAnnotation != null); PropertyInfo info = clrTypeAnnotation.ClrType.GetProperty(property.Name); Contract.Assert(info != null); return info; }
/// <summary> /// Validates a stream reference property. /// </summary> /// <param name="streamProperty">The stream property to check.</param> /// <param name="structuredType">The owning type of the stream property or null if no metadata is available.</param> /// <param name="streamEdmProperty">The stream property defined by the model.</param> /// <param name="messageReaderSettings">The message reader settings being used.</param> internal static void ValidateStreamReferenceProperty(ODataProperty streamProperty, IEdmStructuredType structuredType, IEdmProperty streamEdmProperty, ODataMessageReaderSettings messageReaderSettings) { Debug.Assert(streamProperty != null, "streamProperty != null"); ValidationUtils.ValidateStreamReferenceProperty(streamProperty, streamEdmProperty); if (structuredType != null && structuredType.IsOpen) { // If no property match was found in the metadata and an error wasn't raised, // it is an open property (which is not supported for streams). if (streamEdmProperty == null && !messageReaderSettings.ReportUndeclaredLinkProperties) { // Fails with the correct error message. ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, streamProperty.Value); } } }
/// <summary> /// Validates a stream reference property. /// </summary> /// <param name="streamProperty">The stream property to check.</param> /// <param name="structuredType">The owning type of the stream property or null if no metadata is available.</param> /// <param name="streamEdmProperty">The stream property defined by the model.</param> internal static void ValidateStreamReferenceProperty(ODataProperty streamProperty, IEdmStructuredType structuredType, IEdmProperty streamEdmProperty) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(streamProperty != null, "streamProperty != null"); ValidationUtils.ValidateStreamReferenceProperty(streamProperty, streamEdmProperty); if (structuredType != null && structuredType.IsOpen) { // If no property match was found in the metadata and an error wasn't raised, // it is an open property (which is not supported for streams). if (streamEdmProperty == null) { // Fails with the correct error message. ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, streamProperty.Value); } } }
/// <summary> /// Adds a transient annotation to indicate how null values for the specified property should be read. /// </summary> /// <param name="model">The <see cref="IEdmModel"/> containing the annotations.</param> /// <param name="property">The <see cref="IEdmProperty"/> to modify.</param> /// <param name="nullValueReadBehaviorKind">The new behavior for reading null values for this property.</param> public static void SetNullValueReaderBehavior(this IEdmModel model, IEdmProperty property, ODataNullValueBehaviorKind nullValueReadBehaviorKind) { ExceptionUtils.CheckArgumentNotNull(model, "model"); ExceptionUtils.CheckArgumentNotNull(property, "property"); ODataEdmPropertyAnnotation annotation = model.GetAnnotationValue<ODataEdmPropertyAnnotation>(property); if (annotation == null) { if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.Default) { annotation = new ODataEdmPropertyAnnotation { NullValueReadBehaviorKind = nullValueReadBehaviorKind }; model.SetAnnotationValue(property, annotation); } } else { annotation.NullValueReadBehaviorKind = nullValueReadBehaviorKind; } }
internal ClientPropertyAnnotation(IEdmProperty edmProperty, PropertyInfo propertyInfo, DataServiceProtocolVersion maxProtocolVersion) { ParameterExpression expression; ParameterExpression expression2; this.EdmProperty = edmProperty; this.PropertyName = propertyInfo.Name; this.NullablePropertyType = propertyInfo.PropertyType; this.PropertyType = Nullable.GetUnderlyingType(this.NullablePropertyType) ?? this.NullablePropertyType; this.DeclaringClrType = propertyInfo.DeclaringType; MethodInfo getMethod = propertyInfo.GetGetMethod(); MethodInfo setMethod = propertyInfo.GetSetMethod(); this.propertyGetter = (getMethod == null) ? null : ((Func<object, object>) Expression.Lambda(Expression.Convert(Expression.Call(Expression.Convert(expression = Expression.Parameter(typeof(object), "instance"), this.DeclaringClrType), getMethod), typeof(object)), new ParameterExpression[] { expression }).Compile()); this.propertySetter = (setMethod == null) ? null : ((Action<object, object>) Expression.Lambda(Expression.Call(Expression.Convert(expression, this.DeclaringClrType), setMethod, new Expression[] { Expression.Convert(expression2 = Expression.Parameter(typeof(object), "value"), this.NullablePropertyType) }), new ParameterExpression[] { expression, expression2 }).Compile()); this.MaxProtocolVersion = maxProtocolVersion; this.IsKnownType = PrimitiveType.IsKnownType(this.PropertyType); if (!this.IsKnownType) { MethodInfo method = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(IDictionary<,>), "set_Item", out this.DictionaryValueType); if (method != null) { ParameterExpression expression3; this.dictionarySetter = (Action<object, string, object>) Expression.Lambda(Expression.Call(Expression.Convert(expression, typeof(IDictionary<,>).MakeGenericType(new Type[] { typeof(string), this.DictionaryValueType })), method, expression3 = Expression.Parameter(typeof(string), "propertyName"), Expression.Convert(expression2, this.DictionaryValueType)), new ParameterExpression[] { expression, expression3, expression2 }).Compile(); } else { MethodInfo info4 = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection<>), "Contains", out this.collectionGenericType); MethodInfo addToCollectionMethod = ClientTypeUtil.GetAddToCollectionMethod(this.PropertyType, out this.collectionGenericType); MethodInfo info6 = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection<>), "Remove", out this.collectionGenericType); MethodInfo info7 = ClientTypeUtil.GetMethodForGenericType(this.PropertyType, typeof(ICollection<>), "Clear", out this.collectionGenericType); this.collectionContains = (info4 == null) ? null : ((Func<object, object, bool>) Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), info4, new Expression[] { Expression.Convert(expression2, this.collectionGenericType) }), new ParameterExpression[] { expression, expression2 }).Compile()); this.collectionAdd = (addToCollectionMethod == null) ? null : ((Action<object, object>) Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), addToCollectionMethod, new Expression[] { Expression.Convert(expression2, this.collectionGenericType) }), new ParameterExpression[] { expression, expression2 }).Compile()); this.collectionRemove = (info6 == null) ? null : ((Func<object, object, bool>) Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), info6, new Expression[] { Expression.Convert(expression2, this.collectionGenericType) }), new ParameterExpression[] { expression, expression2 }).Compile()); this.collectionClear = (info7 == null) ? null : ((Action<object>) Expression.Lambda(Expression.Call(Expression.Convert(expression, this.PropertyType), info7), new ParameterExpression[] { expression }).Compile()); } } }
/// <summary> /// Gets the property and structured type from <see cref="ODataPath"/>. /// TODO: The logic implenetation is not good and do need refactor it later. /// </summary> /// <param name="path">The OData path.</param> /// <returns>The property, structured type and the name.</returns> internal static (IEdmProperty, IEdmStructuredType, string) GetPropertyAndStructuredTypeFromPath(this ODataPath path) { if (path == null) { return(null, null, string.Empty); } IEdmStructuredType structuredType = null; string typeCast = string.Empty; IEnumerable <ODataPathSegment> reverseSegments = path.Reverse(); foreach (var segment in reverseSegments) { if (segment is NavigationPropertySegment navigationPathSegment) { IEdmProperty property = navigationPathSegment.NavigationProperty; if (structuredType == null) { structuredType = navigationPathSegment.NavigationProperty.ToEntityType(); } string name = navigationPathSegment.NavigationProperty.Name + typeCast; return(property, structuredType, name); } if (segment is OperationSegment operationSegment) { if (structuredType == null) { structuredType = operationSegment.EdmType as IEdmStructuredType; } string name = operationSegment.Operations.First().FullName() + typeCast; return(null, structuredType, name); } if (segment is PropertySegment propertyAccessPathSegment) { IEdmProperty property = propertyAccessPathSegment.Property; if (structuredType == null) { structuredType = property.Type.GetElementType() as IEdmStructuredType; } string name = property.Name + typeCast; return(property, structuredType, name); } if (segment is EntitySetSegment entitySetSegment) { if (structuredType == null) { structuredType = entitySetSegment.EntitySet.EntityType(); } string name = entitySetSegment.EntitySet.Name + typeCast; return(null, structuredType, name); } if (segment is SingletonSegment singletonSegment) { if (structuredType == null) { structuredType = singletonSegment.Singleton.EntityType(); } string name = singletonSegment.Singleton.Name + typeCast; return(null, structuredType, name); } if (segment is TypeSegment typeSegment) { structuredType = typeSegment.EdmType.AsElementType() as IEdmStructuredType; typeCast = "/" + structuredType; } else if (segment is KeySegment || segment is CountSegment) { // do nothing, just go to next segment, what about if meet OperationSegment? } else { // if we meet any other segments, just return (null, null, string.Empty); break; } } return(null, null, string.Empty); }
/// <summary> /// Generate an expand item (and a select item for the implicit nav prop if necessary) based on an ExpandTermToken /// </summary> /// <param name="tokenIn">the expandTerm token to visit</param> /// <returns>the expand item for this expand term token.</returns> private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); // ensure that we're always dealing with proper V4 syntax if (tokenIn.PathToNavProp.NextToken != null && !tokenIn.PathToNavProp.IsNamespaceOrContainerQualified()) { if (tokenIn.PathToNavProp.NextToken.Identifier != UriQueryConstants.RefSegment || tokenIn.PathToNavProp.NextToken.NextToken != null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } PathSegmentToken currentToken = tokenIn.PathToNavProp; IEdmStructuredType currentLevelEntityType = this.EdmType; List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); PathSegmentToken firstNonTypeToken = currentToken; if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelEntityType, out firstNonTypeToken)); } IEdmProperty edmProperty = this.configuration.Resolver.ResolveProperty(currentLevelEntityType, firstNonTypeToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentLevelEntityType.ODataFullName(), currentToken.Identifier)); } IEdmNavigationProperty currentNavProp = edmProperty as IEdmNavigationProperty; if (currentNavProp == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationProperty(currentToken.Identifier, currentLevelEntityType.ODataFullName())); } bool isRef = false; if (firstNonTypeToken.NextToken != null) { // lastly... make sure that, since we're on a NavProp, that the next token isn't null. if (firstNonTypeToken.NextToken.Identifier == UriQueryConstants.RefSegment) { isRef = true; } else { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } pathSoFar.Add(new NavigationPropertySegment(currentNavProp, /*entitySet*/ null)); ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); IEdmNavigationSource targetNavigationSource = null; if (this.NavigationSource != null) { targetNavigationSource = this.NavigationSource.FindNavigationTarget(currentNavProp); } // call MetadataBinder to build the filter clause FilterClause filterOption = null; if (tokenIn.FilterOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); FilterBinder filterBinder = new FilterBinder(binder.Bind, binder.BindingState); filterOption = filterBinder.BindFilter(tokenIn.FilterOption); } // call MetadataBinder again to build the orderby clause OrderByClause orderbyOption = null; if (tokenIn.OrderByOptions != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); orderbyOption = orderByBinder.BindOrderBy(binder.BindingState, tokenIn.OrderByOptions); } SearchClause searchOption = null; if (tokenIn.SearchOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); SearchBinder searchBinder = new SearchBinder(binder.Bind); searchOption = searchBinder.BindSearch(tokenIn.SearchOption); } if (isRef) { return(new ExpandedReferenceSelectItem(pathToNavProp, targetNavigationSource, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption)); } SelectExpandClause subSelectExpand; if (tokenIn.ExpandOption != null) { subSelectExpand = this.GenerateSubExpand(currentNavProp, tokenIn); } else { subSelectExpand = BuildDefaultSubExpand(); } subSelectExpand = this.DecorateExpandWithSelect(subSelectExpand, currentNavProp, tokenIn.SelectOption); LevelsClause levelsOption = this.ParseLevels(tokenIn.LevelsOption, currentLevelEntityType, currentNavProp); return(new ExpandedNavigationSelectItem(pathToNavProp, targetNavigationSource, subSelectExpand, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption, levelsOption)); }
public CustomersModelWithInheritance() { EdmModel model = new EdmModel(); // Enum type simpleEnum EdmEnumType simpleEnum = new EdmEnumType("NS", "SimpleEnum"); simpleEnum.AddMember(new EdmEnumMember(simpleEnum, "First", new EdmEnumMemberValue(0))); simpleEnum.AddMember(new EdmEnumMember(simpleEnum, "Second", new EdmEnumMemberValue(1))); simpleEnum.AddMember(new EdmEnumMember(simpleEnum, "Third", new EdmEnumMemberValue(2))); model.AddElement(simpleEnum); // complex type address EdmComplexType address = new EdmComplexType("NS", "Address"); address.AddStructuralProperty("Street", EdmPrimitiveTypeKind.String); address.AddStructuralProperty("City", EdmPrimitiveTypeKind.String); address.AddStructuralProperty("State", EdmPrimitiveTypeKind.String); address.AddStructuralProperty("ZipCode", EdmPrimitiveTypeKind.String); address.AddStructuralProperty("CountryOrRegion", EdmPrimitiveTypeKind.String); model.AddElement(address); // open complex type "Account" EdmComplexType account = new EdmComplexType("NS", "Account", null, false, true); account.AddStructuralProperty("Bank", EdmPrimitiveTypeKind.String); account.AddStructuralProperty("CardNum", EdmPrimitiveTypeKind.Int64); account.AddStructuralProperty("BankAddress", new EdmComplexTypeReference(address, isNullable: true)); model.AddElement(account); EdmComplexType specialAccount = new EdmComplexType("NS", "SpecialAccount", account, false, true); specialAccount.AddStructuralProperty("SpecialCard", EdmPrimitiveTypeKind.String); model.AddElement(specialAccount); // entity type customer EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("ID", EdmPrimitiveTypeKind.Int32)); IEdmProperty customerName = customer.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String); customer.AddStructuralProperty("SimpleEnum", simpleEnum.ToEdmTypeReference(isNullable: false)); customer.AddStructuralProperty("Address", new EdmComplexTypeReference(address, isNullable: true)); customer.AddStructuralProperty("Account", new EdmComplexTypeReference(account, isNullable: true)); IEdmTypeReference primitiveTypeReference = EdmCoreModel.Instance.GetPrimitive( EdmPrimitiveTypeKind.String, isNullable: true); var city = customer.AddStructuralProperty( "City", primitiveTypeReference, defaultValue: null); model.AddElement(customer); // derived entity type special customer EdmEntityType specialCustomer = new EdmEntityType("NS", "SpecialCustomer", customer); specialCustomer.AddStructuralProperty("SpecialCustomerProperty", EdmPrimitiveTypeKind.Guid); specialCustomer.AddStructuralProperty("SpecialAddress", new EdmComplexTypeReference(address, isNullable: true)); model.AddElement(specialCustomer); // entity type order (open entity type) EdmEntityType order = new EdmEntityType("NS", "Order", null, false, true); // EdmEntityType order = new EdmEntityType("NS", "Order"); order.AddKeys(order.AddStructuralProperty("ID", EdmPrimitiveTypeKind.Int32)); order.AddStructuralProperty("City", EdmPrimitiveTypeKind.String); order.AddStructuralProperty("Amount", EdmPrimitiveTypeKind.Int32); model.AddElement(order); // derived entity type special order EdmEntityType specialOrder = new EdmEntityType("NS", "SpecialOrder", order, false, true); specialOrder.AddStructuralProperty("SpecialOrderProperty", EdmPrimitiveTypeKind.Guid); model.AddElement(specialOrder); // test entity EdmEntityType testEntity = new EdmEntityType("Microsoft.Test.AspNet.OData.Query.Expressions", "TestEntity"); testEntity.AddStructuralProperty("SampleProperty", EdmPrimitiveTypeKind.Binary); model.AddElement(testEntity); // containment // my order EdmEntityType myOrder = new EdmEntityType("NS", "MyOrder"); myOrder.AddKeys(myOrder.AddStructuralProperty("ID", EdmPrimitiveTypeKind.Int32)); myOrder.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String); model.AddElement(myOrder); // order line EdmEntityType orderLine = new EdmEntityType("NS", "OrderLine"); orderLine.AddKeys(orderLine.AddStructuralProperty("ID", EdmPrimitiveTypeKind.Int32)); orderLine.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String); model.AddElement(orderLine); EdmNavigationProperty orderLinesNavProp = myOrder.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "OrderLines", TargetMultiplicity = EdmMultiplicity.Many, Target = orderLine, ContainsTarget = true, }); EdmNavigationProperty nonContainedOrderLinesNavProp = myOrder.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "NonContainedOrderLines", TargetMultiplicity = EdmMultiplicity.Many, Target = orderLine, ContainsTarget = false, }); EdmAction tag = new EdmAction("NS", "tag", returnType: null, isBound: true, entitySetPathExpression: null); tag.AddParameter("entity", new EdmEntityTypeReference(orderLine, false)); model.AddElement(tag); // entity sets EdmEntityContainer container = new EdmEntityContainer("NS", "ModelWithInheritance"); model.AddElement(container); EdmEntitySet customers = container.AddEntitySet("Customers", customer); EdmEntitySet orders = container.AddEntitySet("Orders", order); EdmEntitySet myOrders = container.AddEntitySet("MyOrders", myOrder); // singletons EdmSingleton vipCustomer = container.AddSingleton("VipCustomer", customer); EdmSingleton mary = container.AddSingleton("Mary", customer); EdmSingleton rootOrder = container.AddSingleton("RootOrder", order); // annotations model.SetOptimisticConcurrencyAnnotation(customers, new[] { city }); // containment IEdmContainedEntitySet orderLines = (IEdmContainedEntitySet)myOrders.FindNavigationTarget(orderLinesNavProp); // no-containment IEdmNavigationSource nonContainedOrderLines = myOrders.FindNavigationTarget(nonContainedOrderLinesNavProp); // actions EdmAction upgrade = new EdmAction("NS", "upgrade", returnType: null, isBound: true, entitySetPathExpression: null); upgrade.AddParameter("entity", new EdmEntityTypeReference(customer, false)); model.AddElement(upgrade); EdmAction specialUpgrade = new EdmAction("NS", "specialUpgrade", returnType: null, isBound: true, entitySetPathExpression: null); specialUpgrade.AddParameter("entity", new EdmEntityTypeReference(specialCustomer, false)); model.AddElement(specialUpgrade); // actions bound to collection EdmAction upgradeAll = new EdmAction("NS", "UpgradeAll", returnType: null, isBound: true, entitySetPathExpression: null); upgradeAll.AddParameter("entityset", new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(customer, false)))); model.AddElement(upgradeAll); EdmAction upgradeSpecialAll = new EdmAction("NS", "UpgradeSpecialAll", returnType: null, isBound: true, entitySetPathExpression: null); upgradeSpecialAll.AddParameter("entityset", new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(specialCustomer, false)))); model.AddElement(upgradeSpecialAll); // functions IEdmTypeReference returnType = EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Boolean, isNullable: false); IEdmTypeReference stringType = EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.String, isNullable: false); IEdmTypeReference intType = EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Int32, isNullable: false); EdmFunction IsUpgraded = new EdmFunction( "NS", "IsUpgraded", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); IsUpgraded.AddParameter("entity", new EdmEntityTypeReference(customer, false)); model.AddElement(IsUpgraded); EdmFunction orderByCityAndAmount = new EdmFunction( "NS", "OrderByCityAndAmount", stringType, isBound: true, entitySetPathExpression: null, isComposable: false); orderByCityAndAmount.AddParameter("entity", new EdmEntityTypeReference(customer, false)); orderByCityAndAmount.AddParameter("city", stringType); orderByCityAndAmount.AddParameter("amount", intType); model.AddElement(orderByCityAndAmount); EdmFunction getOrders = new EdmFunction( "NS", "GetOrders", EdmCoreModel.GetCollection(order.ToEdmTypeReference(false)), isBound: true, entitySetPathExpression: null, isComposable: true); getOrders.AddParameter("entity", new EdmEntityTypeReference(customer, false)); getOrders.AddParameter("parameter", intType); model.AddElement(getOrders); EdmFunction IsSpecialUpgraded = new EdmFunction( "NS", "IsSpecialUpgraded", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); IsSpecialUpgraded.AddParameter("entity", new EdmEntityTypeReference(specialCustomer, false)); model.AddElement(IsSpecialUpgraded); EdmFunction getSalary = new EdmFunction( "NS", "GetSalary", stringType, isBound: true, entitySetPathExpression: null, isComposable: false); getSalary.AddParameter("entity", new EdmEntityTypeReference(customer, false)); model.AddElement(getSalary); getSalary = new EdmFunction( "NS", "GetSalary", stringType, isBound: true, entitySetPathExpression: null, isComposable: false); getSalary.AddParameter("entity", new EdmEntityTypeReference(specialCustomer, false)); model.AddElement(getSalary); EdmFunction IsAnyUpgraded = new EdmFunction( "NS", "IsAnyUpgraded", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); EdmCollectionType edmCollectionType = new EdmCollectionType(new EdmEntityTypeReference(customer, false)); IsAnyUpgraded.AddParameter("entityset", new EdmCollectionTypeReference(edmCollectionType)); model.AddElement(IsAnyUpgraded); EdmFunction isCustomerUpgradedWithParam = new EdmFunction( "NS", "IsUpgradedWithParam", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); isCustomerUpgradedWithParam.AddParameter("entity", new EdmEntityTypeReference(customer, false)); isCustomerUpgradedWithParam.AddParameter("city", EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.String, isNullable: false)); model.AddElement(isCustomerUpgradedWithParam); EdmFunction isCustomerLocal = new EdmFunction( "NS", "IsLocal", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); isCustomerLocal.AddParameter("entity", new EdmEntityTypeReference(customer, false)); model.AddElement(isCustomerLocal); EdmFunction entityFunction = new EdmFunction( "NS", "GetCustomer", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); entityFunction.AddParameter("entity", new EdmEntityTypeReference(customer, false)); entityFunction.AddParameter("customer", new EdmEntityTypeReference(customer, false)); model.AddElement(entityFunction); EdmFunction getOrder = new EdmFunction( "NS", "GetOrder", order.ToEdmTypeReference(false), isBound: true, entitySetPathExpression: null, isComposable: true); // Composable getOrder.AddParameter("entity", new EdmEntityTypeReference(customer, false)); getOrder.AddParameter("orderId", intType); model.AddElement(getOrder); // functions bound to collection EdmFunction isAllUpgraded = new EdmFunction("NS", "IsAllUpgraded", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); isAllUpgraded.AddParameter("entityset", new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(customer, false)))); isAllUpgraded.AddParameter("param", intType); model.AddElement(isAllUpgraded); EdmFunction isSpecialAllUpgraded = new EdmFunction("NS", "IsSpecialAllUpgraded", returnType, isBound: true, entitySetPathExpression: null, isComposable: false); isSpecialAllUpgraded.AddParameter("entityset", new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(specialCustomer, false)))); isSpecialAllUpgraded.AddParameter("param", intType); model.AddElement(isSpecialAllUpgraded); // navigation properties EdmNavigationProperty ordersNavProp = customer.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "Orders", TargetMultiplicity = EdmMultiplicity.Many, Target = order }); mary.AddNavigationTarget(ordersNavProp, orders); vipCustomer.AddNavigationTarget(ordersNavProp, orders); customers.AddNavigationTarget(ordersNavProp, orders); orders.AddNavigationTarget( order.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "Customer", TargetMultiplicity = EdmMultiplicity.ZeroOrOne, Target = customer }), customers); // navigation properties on derived types. EdmNavigationProperty specialOrdersNavProp = specialCustomer.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "SpecialOrders", TargetMultiplicity = EdmMultiplicity.Many, Target = order }); vipCustomer.AddNavigationTarget(specialOrdersNavProp, orders); customers.AddNavigationTarget(specialOrdersNavProp, orders); orders.AddNavigationTarget( specialOrder.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "SpecialCustomer", TargetMultiplicity = EdmMultiplicity.ZeroOrOne, Target = customer }), customers); model.SetAnnotationValue <BindableOperationFinder>(model, new BindableOperationFinder(model)); // set properties Model = model; Container = container; Customer = customer; Order = order; Address = address; Account = account; SpecialCustomer = specialCustomer; SpecialOrder = specialOrder; Orders = orders; Customers = customers; VipCustomer = vipCustomer; Mary = mary; RootOrder = rootOrder; OrderLine = orderLine; OrderLines = orderLines; NonContainedOrderLines = nonContainedOrderLines; UpgradeCustomer = upgrade; UpgradeSpecialCustomer = specialUpgrade; CustomerName = customerName; IsCustomerUpgraded = isCustomerUpgradedWithParam; IsSpecialCustomerUpgraded = IsSpecialUpgraded; Tag = tag; }
/// <inheritdoc /> public override bool TryTranslate(ODataTemplateTranslateContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } RouteValueDictionary routeValues = context.RouteValues; RouteValueDictionary updateValues = context.UpdatedValues; IDictionary <string, object> keysValues = new Dictionary <string, object>(); foreach (var key in KeyMappings) { string keyName = key.Key; string templateName = key.Value; if (routeValues.TryGetValue(templateName, out object rawValue)) { IEdmProperty keyProperty = KeyProperties.FirstOrDefault(k => k.Key == keyName).Value; Contract.Assert(keyProperty != null); IEdmTypeReference edmType = keyProperty.Type; string strValue = rawValue as string; string newStrValue = context.GetParameterAliasOrSelf(strValue); if (newStrValue != strValue) { updateValues[templateName] = newStrValue; strValue = newStrValue; } // If it's key as segment and the key type is Edm.String, we support non-single quoted string. // Since we can't identify key as segment and key in parenthesis easy so far, // we use the key literal with "/" to test in the whole route template. // Why we can't create two key segment templates, one reason is that in attribute routing template, // we can't identify key as segment or key in parenthesis also. if (edmType.IsString() && context.IsPartOfRouteTemplate($"/{_keyLiteral}")) { if (!strValue.StartsWith('\'') && !strValue.EndsWith('\'')) { strValue = $"'{strValue}'"; // prefix and suffix single quote } } object newValue; try { newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, context.Model, edmType); } catch (ODataException ex) { string message = Error.Format(SRResources.InvalidKeyInUriFound, strValue, edmType.FullName()); throw new ODataException(message, ex); } // for non FromODataUri, so update it, for example, remove the single quote for string value. updateValues[templateName] = newValue; // For FromODataUri, let's refactor it later. string prefixName = ODataParameterValue.ParameterValuePrefix + templateName; updateValues[prefixName] = new ODataParameterValue(newValue, edmType); keysValues[keyName] = newValue; } } context.Segments.Add(new KeySegment(keysValues, EntityType, NavigationSource)); return(true); }
internal Expression CreatePropertyValueExpression(IEdmEntityType elementType, IEdmProperty property, Expression source) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); return(CreatePropertyValueExpressionWithFilter(elementType, property, source, filterClause: null)); }
/// <summary> /// Reads the content of a properties in an element (complex value, m:properties, ...) /// </summary> /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param> /// <param name="properties">The list of properties to add properties to.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The element to read properties from. /// Post-Condition: XmlNodeType.Element - The element to read properties from if it is an empty element. /// XmlNodeType.EndElement - The end element of the element to read properties from. /// </remarks> private void ReadPropertiesImplementation(IEdmStructuredType structuredType, ReadOnlyEnumerable <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(properties != null, "properties != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertXmlCondition(XmlNodeType.Element); // Empty values are valid - they have no properties if (!this.XmlReader.IsEmptyElement) { // Read over the complex value element to its first child node (or end-element) this.XmlReader.ReadStartElement(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { // Found a property IEdmProperty edmProperty = null; bool isOpen = false; bool ignoreProperty = false; if (structuredType != null) { // Lookup the property in metadata edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty); if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation) { throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType)); } // If the property was not declared, it must be open. isOpen = edmProperty == null; } if (ignoreProperty) { this.XmlReader.Skip(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); ODataProperty property = this.ReadProperty( false, edmProperty == null ? null : edmProperty.Name, edmProperty == null ? null : edmProperty.Type, nullValueReadBehaviorKind); Debug.Assert( property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue, "If we don't ignore null values the property must not be null."); if (property != null) { if (isOpen) { ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); properties.AddToSourceList(property); } } } else { this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // End of the complex value. break; default: // Non-element so for example a text node, just ignore this.XmlReader.Skip(); break; } }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } }
internal static void SetCollectionProperty(object resource, IEdmProperty edmProperty, object value) { Contract.Assert(edmProperty != null); SetCollectionProperty(resource, edmProperty.Name, edmProperty.Type.AsCollection(), value, clearCollection: false); }
/// <summary> /// Validates a stream reference property to ensure it's not null and its name if correct. /// </summary> /// <param name="streamProperty">The stream reference property to validate.</param> /// <param name="edmProperty">Property metadata to validate against.</param> internal static void ValidateStreamReferenceProperty(ODataProperty streamProperty, IEdmProperty edmProperty) { Debug.Assert(streamProperty != null, "streamProperty != null"); Debug.Assert(!string.IsNullOrEmpty(streamProperty.Name), "!string.IsNullOrEmpty(streamProperty.Name)"); Debug.Assert(streamProperty.Value is ODataStreamReferenceValue, "This method should only be called for stream reference properties."); Debug.Assert(edmProperty == null || edmProperty.Name == streamProperty.Name, "edmProperty == null || edmProperty.Name == streamProperty.Name"); if (edmProperty != null && !edmProperty.Type.IsStream()) { throw new ODataException(Strings.ValidationUtils_MismatchPropertyKindForStreamProperty(streamProperty.Name)); } }
/// <summary> /// Gets the instance of ClientTypeAnnotation from the given instance of <paramref name="edmProperty"/>. /// </summary> /// <param name="model">The model.</param> /// <param name="edmProperty">IEdmProperty instance to get the annotation.</param> /// <returns>Returns the instance of ClientTypeAnnotation from the given instance of <paramref name="edmProperty"/>.</returns> internal static ClientTypeAnnotation GetClientTypeAnnotation(this IEdmModel model, IEdmProperty edmProperty) { Debug.Assert(model != null, "model != null"); Debug.Assert(edmProperty != null, "edmProperty != null"); IEdmType edmType = edmProperty.Type.Definition; Debug.Assert(edmType != null, "edmType != null"); return(model.GetAnnotationValue <ClientTypeAnnotation>(edmType)); }
private static void SetComputedAnnotation(EdmModel model, IEdmProperty target) { // when 'target' is <Key> property, V4's 'Computed' also has the meaning of OData V3's 'Identity'. var val = new EdmBooleanConstant(value: true); var annotation = new EdmAnnotation(target, CoreVocabularyModel.ComputedTerm, val); annotation.SetSerializationLocation(model, EdmVocabularyAnnotationSerializationLocation.Inline); model.SetVocabularyAnnotation(annotation); }
public static IQueryable OrderByProperty(IQueryable query, IEdmProperty property, OrderByDirection direction, Type type, bool alreadyOrdered = false) { LambdaExpression orderByLambda = GetPropertyAccessLambda(type, property.Name); return OrderBy(query, orderByLambda, direction, type, alreadyOrdered); }
protected virtual void ProcessProperty(IEdmProperty property) { this.ProcessVocabularyAnnotatable(property); this.ProcessNamedElement(property); this.VisitTypeReference(property.Type); }
public static PropertyInfo GetPropertyIgnoreCaseOrNull(this Type declaringType, IEdmProperty edmProperty) { var schemaElement = (IEdmSchemaElement)edmProperty.DeclaringType; do { if (String.Compare(declaringType.Name, schemaElement.Name, StringComparison.OrdinalIgnoreCase) == 0 && String.Compare(declaringType.Namespace, schemaElement.Namespace, StringComparison.OrdinalIgnoreCase) == 0) { PropertyInfo propertyInfo = declaringType.GetPropertyIgnoreCase(edmProperty.Name); if (propertyInfo == null) { if (edmProperty is OeEdmStructuralShadowProperty structuralShadowProperty) { return(Parsers.OeExpressionHelper.IsTupleType(declaringType) ? null : structuralShadowProperty.PropertyInfo); } if (edmProperty is OeEdmNavigationShadowProperty navigationShadowProperty) { return(Parsers.OeExpressionHelper.IsTupleType(declaringType) ? null : navigationShadowProperty.PropertyInfo); } } return(propertyInfo); } declaringType = declaringType.BaseType; }while (declaringType != null); return(null); }
public static PropertyInfo GetPropertyIgnoreCase(this Type declaringType, IEdmProperty edmProperty) { return(declaringType.GetPropertyIgnoreCaseOrNull(edmProperty) ?? throw new InvalidOperationException("EdmProperty " + edmProperty.Name + " not found in type " + declaringType.FullName)); }
/// <summary> /// Binds a <see cref="InnerPathToken"/>. /// This includes more than just navigations - it includes complex property access and primitive collections. /// </summary> /// <param name="segmentToken">The segment token to bind.</param> /// <returns>The bound node.</returns> internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod, state); // First we get the parent node QueryNode parent = this.DetermineParentNode(segmentToken, state); Debug.Assert(parent != null, "parent should never be null"); SingleValueNode singleValueParent = parent as SingleValueNode; if (singleValueParent == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(segmentToken.Identifier)); } // Using the parent and name of this token, we try to get the IEdmProperty it represents IEdmProperty property = BindProperty(singleValueParent.TypeReference, segmentToken.Identifier, this.Resolver); if (property == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpen()) { throw new ODataException( ODataErrorStrings.MetadataBinder_PropertyNotDeclared( parent.GetEdmTypeReference().FullName(), segmentToken.Identifier)); } return(new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier)); } IEdmStructuralProperty structuralProperty = property as IEdmStructuralProperty; if (property.Type.IsComplex()) { // Generate a segment to parsed segments for the parsed token state.ParsedSegments.Add(new PropertySegment(structuralProperty)); return(new SingleComplexNode(singleValueParent as SingleResourceNode, property)); } else if (property.Type.IsPrimitive()) { return(new SingleValuePropertyAccessNode(singleValueParent, property)); } // Note - this means nonentity collection (primitive or complex) if (property.Type.IsNonEntityCollectionType()) { if (property.Type.IsStructuredCollectionType()) { // Generate a segment to parsed segments for the parsed token state.ParsedSegments.Add(new PropertySegment(structuralProperty)); return(new CollectionComplexNode(singleValueParent as SingleResourceNode, property)); } return(new CollectionPropertyAccessNode(singleValueParent, property)); } IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name)); } SingleResourceNode parentResource = EnsureParentIsResourceForNavProp(singleValueParent); IEdmNavigationSource navigationSource; QueryNode node = GetNavigationNode(navigationProperty, parentResource, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod), out navigationSource); // Generate a segment to parsed segments for the parsed token state.ParsedSegments.Add(new NavigationPropertySegment(navigationProperty, navigationSource)); return(node); }
public static bool IsNotCountable(IEdmProperty edmProperty, IEdmModel edmModel) { QueryableRestrictionsAnnotation annotation = GetPropertyRestrictions(edmProperty, edmModel); return(annotation == null ? false : annotation.Restrictions.NotCountable); }
public OeSelectItem(IEdmProperty edmProperty, bool skipToken) : this() { EdmProperty = edmProperty; SkipToken = skipToken; }
/// <summary> /// Returns the text representation of the current object. /// </summary> /// <param name="property">Reference to the calling object.</param> /// <returns>The text representation of the current object.</returns> public static string ToTraceString(this IEdmProperty property) { EdmUtil.CheckArgumentNull(property, "property"); return((property.Name != null ? property.Name : "") + ":" + (property.Type != null ? property.Type.ToTraceString() : "")); }
/// <summary> /// Gets the single instance of ClientPropertyAnnotation from the given instance of <paramref name="edmProperty"/>. /// </summary> /// <param name="model">The model.</param> /// <param name="edmProperty">IEdmProperty instance to get the annotation.</param> /// <returns>Returns the single instance of ClientPropertyAnnotation from the given instance of <paramref name="edmProperty"/>.</returns> internal static ClientPropertyAnnotation GetClientPropertyAnnotation(this IEdmModel model, IEdmProperty edmProperty) { Debug.Assert(model != null, "model != null"); Debug.Assert(edmProperty != null, "edmProperty != null"); return(model.GetAnnotationValue <ClientPropertyAnnotation>(edmProperty)); }
internal Expression CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType, IEdmProperty property, Expression source, FilterClause filterClause) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException("TODO: " /*Error.Format(SRResources.MappingDoesNotContainResourceType, * declaringType.FullName())*/); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); Expression propertyValue = Expression.Property(source, propertyName); Type nullablePropertyType = propertyValue.Type.ToNullable(); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); if (filterClause != null && property.Type.IsCollection()) { IEdmTypeReference edmElementType = property.Type.AsCollection().ElementType(); Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model); if (clrElementType == null) { throw new ODataException("TODO:" /*Error.Format(SRResources.MappingDoesNotContainResourceType, * edmElementType.FullName())*/); } Expression filterSource = typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType) ? Expression.Call( ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType), nullablePropertyValue) : nullablePropertyValue; Expression filterPredicate = FilterBinder.Bind(filterClause, clrElementType, /*_context.RequestContainer*/ null); MethodCallExpression filterResult = Expression.Call( ExpressionHelperMethods.QueryableWhereGeneric.MakeGenericMethod(clrElementType), filterSource, filterPredicate); nullablePropertyType = filterResult.Type; if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // nullablePropertyValue == null ? null : filterResult nullablePropertyValue = Expression.Condition( test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: filterResult); } else { nullablePropertyValue = filterResult; } } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : propertyValue propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: nullablePropertyValue); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = nullablePropertyValue; } return(propertyValue); }
internal Expression CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType, IEdmProperty property, Expression source, FilterClause filterClause) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, declaringType.FullName())); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); Expression propertyValue = Expression.Property(source, propertyName); Type nullablePropertyType = TypeHelper.ToNullable(propertyValue.Type); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); if (filterClause != null) { bool isCollection = property.Type.IsCollection(); IEdmTypeReference edmElementType = (isCollection ? property.Type.AsCollection().ElementType() : property.Type); Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model); if (clrElementType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, edmElementType.FullName())); } Expression filterResult = nullablePropertyValue; ODataQuerySettings querySettings = new ODataQuerySettings() { HandleNullPropagation = HandleNullPropagationOption.True, }; if (isCollection) { Expression filterSource = typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType) ? Expression.Call( ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType), nullablePropertyValue) : nullablePropertyValue; // TODO: Implement proper support for $select/$expand after $apply Expression filterPredicate = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings); filterResult = Expression.Call( ExpressionHelperMethods.QueryableWhereGeneric.MakeGenericMethod(clrElementType), filterSource, filterPredicate); nullablePropertyType = filterResult.Type; } else if (_settings.HandleReferenceNavigationPropertyExpandFilter) { LambdaExpression filterLambdaExpression = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings) as LambdaExpression; if (filterLambdaExpression == null) { throw new ODataException(Error.Format(SRResources.ExpandFilterExpressionNotLambdaExpression, property.Name, "LambdaExpression")); } ParameterExpression filterParameter = filterLambdaExpression.Parameters.First(); Expression predicateExpression = new ReferenceNavigationPropertyExpandFilterVisitor(filterParameter, nullablePropertyValue).Visit(filterLambdaExpression.Body); // create expression similar to: 'predicateExpression == true ? nullablePropertyValue : null' filterResult = Expression.Condition( test: predicateExpression, ifTrue: nullablePropertyValue, ifFalse: Expression.Constant(value: null, type: nullablePropertyType)); } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'nullablePropertyValue == null ? null : filterResult' nullablePropertyValue = Expression.Condition( test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: filterResult); } else { nullablePropertyValue = filterResult; } } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'source == null ? null : propertyValue' propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: nullablePropertyValue); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = nullablePropertyValue; } return(propertyValue); }
/// <summary> /// Sets the given instance of <paramref name="annotation"/> to the given instance of <paramref name="edmProperty"/>. /// </summary> /// <param name="edmProperty">IEdmProperty instance to set the annotation.</param> /// <param name="annotation">Annotation instance to set.</param> internal static void SetClientPropertyAnnotation(this IEdmProperty edmProperty, ClientPropertyAnnotation annotation) { Debug.Assert(edmProperty != null, "edmProperty != null"); Debug.Assert(annotation != null, "annotation != null"); annotation.Model.SetAnnotationValue <ClientPropertyAnnotation>(edmProperty, annotation); }
/// <summary> /// Deserializes the nested property from <paramref name="resourceInfoWrapper"/> into <paramref name="resource"/>. /// </summary> /// <param name="resource">The object into which the nested property should be read.</param> /// <param name="resourceInfoWrapper">The nested resource info.</param> /// <param name="structuredType">The type of the resource.</param> /// <param name="readContext">The deserializer context.</param> public virtual void ApplyNestedProperty(object resource, ODataNestedResourceInfoWrapper resourceInfoWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext) { if (resource == null) { throw Error.ArgumentNull("resource"); } if (resourceInfoWrapper == null) { throw Error.ArgumentNull("resourceInfoWrapper"); } IEdmProperty edmProperty = structuredType.FindProperty(resourceInfoWrapper.NestedResourceInfo.Name); if (edmProperty == null) { if (!structuredType.IsOpen()) { throw new ODataException( Error.Format(SRResources.NestedPropertyNotfound, resourceInfoWrapper.NestedResourceInfo.Name, structuredType.FullName())); } } foreach (ODataItemBase childItem in resourceInfoWrapper.NestedItems) { // it maybe null. if (childItem == null) { if (edmProperty == null) { // for the dynamic, OData.net has a bug. see https://github.com/OData/odata.net/issues/977 ApplyDynamicResourceInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource, structuredType, null, readContext); } else { ApplyResourceInNestedProperty(edmProperty, resource, null, readContext); } } ODataEntityReferenceLinkBase entityReferenceLink = childItem as ODataEntityReferenceLinkBase; if (entityReferenceLink != null) { // ignore entity reference links. continue; } ODataResourceSetWrapper resourceSetWrapper = childItem as ODataResourceSetWrapper; if (resourceSetWrapper != null) { if (edmProperty == null) { ApplyDynamicResourceSetInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource, structuredType, resourceSetWrapper, readContext); } else { ApplyResourceSetInNestedProperty(edmProperty, resource, resourceSetWrapper, readContext); } continue; } // It must be resource by now. ODataResourceWrapper resourceWrapper = (ODataResourceWrapper)childItem; if (resourceWrapper != null) { if (edmProperty == null) { ApplyDynamicResourceInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource, structuredType, resourceWrapper, readContext); } else { ApplyResourceInNestedProperty(edmProperty, resource, resourceWrapper, readContext); } } } }
//----------------------------------------------------------------------------------------------------------------------------------------------------- private void SetPropertyItemStyle( IEdmEntityType entityType, IEdmProperty property, out string itemText, out string tooltipText, out ExplorerItemKind itemKind, out ExplorerIcon itemIcon) { var navigationProperty = (property as IEdmNavigationProperty); var structuralProperty = (property as IEdmStructuralProperty); var isCollection = property.Type.IsCollection(); if ( navigationProperty != null ) { itemText = property.Name; tooltipText = property.Type.Definition.FullTypeName(); itemKind = (isCollection ? ExplorerItemKind.CollectionLink : ExplorerItemKind.ReferenceLink); switch (navigationProperty.TargetMultiplicity()) { case EdmMultiplicity.One: itemIcon = (isCollection ? ExplorerIcon.ManyToOne : ExplorerIcon.OneToOne); break; case EdmMultiplicity.Many: itemIcon = (isCollection ? ExplorerIcon.ManyToMany : ExplorerIcon.OneToMany); break; default: itemIcon = ExplorerIcon.Column; break; } } else if (structuralProperty != null && entityType.DeclaredKey.Contains(structuralProperty)) { itemText = string.Format("{0} : {1}", property.Name, property.Type.Definition.FullTypeName()); tooltipText = "Contained in entity key"; itemKind = ExplorerItemKind.Property; itemIcon = ExplorerIcon.Key; } else { itemText = string.Format("{0} : {1}", property.Name, property.Type.Definition.FullTypeName()); tooltipText = string.Empty; itemKind = ExplorerItemKind.Property; itemIcon = ExplorerIcon.Column; } }
private IOrderedQueryable ApplyToCore(IQueryable query, ODataQuerySettings querySettings) { if (Context.ElementClrType == null) { throw Error.NotSupported(SRResources.ApplyToOnUntypedQueryOption, "ApplyTo"); } ICollection <OrderByNode> nodes = OrderByNodes; bool alreadyOrdered = false; IQueryable querySoFar = query; HashSet <IEdmProperty> propertiesSoFar = new HashSet <IEdmProperty>(); bool orderByItSeen = false; foreach (OrderByNode node in nodes) { OrderByPropertyNode propertyNode = node as OrderByPropertyNode; if (propertyNode != null) { IEdmProperty property = propertyNode.Property; OrderByDirection direction = propertyNode.Direction; // This check prevents queries with duplicate properties (e.g. $orderby=Id,Id,Id,Id...) from causing stack overflows if (propertiesSoFar.Contains(property)) { throw new ODataException(Error.Format(SRResources.OrderByDuplicateProperty, property.Name)); } propertiesSoFar.Add(property); if (propertyNode.OrderByClause != null) { // Ensure we have decided how to handle null propagation ODataQuerySettings updatedSettings = querySettings; if (querySettings.HandleNullPropagation == HandleNullPropagationOption.Default) { updatedSettings = new ODataQuerySettings(updatedSettings); updatedSettings.HandleNullPropagation = HandleNullPropagationOptionHelper.GetDefaultHandleNullPropagationOption(query); } LambdaExpression orderByExpression = FilterBinder.Bind(propertyNode.OrderByClause, Context.ElementClrType, Context.Model, updatedSettings); querySoFar = ExpressionHelpers.OrderBy(querySoFar, orderByExpression, direction, Context.ElementClrType, alreadyOrdered); } else { querySoFar = ExpressionHelpers.OrderByProperty(querySoFar, Context.Model, property, direction, Context.ElementClrType, alreadyOrdered); } alreadyOrdered = true; } else { // This check prevents queries with duplicate nodes (e.g. $orderby=$it,$it,$it,$it...) from causing stack overflows if (orderByItSeen) { throw new ODataException(Error.Format(SRResources.OrderByDuplicateIt)); } querySoFar = ExpressionHelpers.OrderByIt(querySoFar, node.Direction, Context.ElementClrType, alreadyOrdered); alreadyOrdered = true; orderByItSeen = true; } } return(querySoFar as IOrderedQueryable); }
public static bool IsAutoExpand(IEdmProperty edmProperty, IEdmModel edmModel) { QueryableRestrictionsAnnotation annotation = GetPropertyRestrictions(edmProperty, edmModel); return annotation == null ? false : annotation.Restrictions.AutoExpand; }
public static string GetClrPropertyName(IEdmProperty edmProperty, IEdmModel edmModel) { if (edmProperty == null) { throw Error.ArgumentNull("edmProperty"); } if (edmModel == null) { throw Error.ArgumentNull("edmModel"); } string propertyName = edmProperty.Name; ClrPropertyInfoAnnotation annotation = edmModel.GetAnnotationValue<ClrPropertyInfoAnnotation>(edmProperty); if (annotation != null) { PropertyInfo propertyInfo = annotation.ClrPropertyInfo; if (propertyInfo != null) { propertyName = propertyInfo.Name; } } return propertyName; }
private void CreateStructuralTypeBody(EdmStructuredType type, StructuralTypeConfiguration config) { foreach (PropertyConfiguration property in config.Properties) { IEdmProperty edmProperty = null; switch (property.Kind) { case PropertyKind.Primitive: PrimitivePropertyConfiguration primitiveProperty = (PrimitivePropertyConfiguration)property; EdmPrimitiveTypeKind typeKind = primitiveProperty.TargetEdmTypeKind ?? GetTypeKind(primitiveProperty.PropertyInfo.PropertyType); IEdmTypeReference primitiveTypeReference = EdmCoreModel.Instance.GetPrimitive( typeKind, primitiveProperty.OptionalProperty); if (typeKind == EdmPrimitiveTypeKind.Decimal) { DecimalPropertyConfiguration decimalProperty = primitiveProperty as DecimalPropertyConfiguration; if (decimalProperty.Precision.HasValue || decimalProperty.Scale.HasValue) { primitiveTypeReference = new EdmDecimalTypeReference( (IEdmPrimitiveType)primitiveTypeReference.Definition, primitiveTypeReference.IsNullable, decimalProperty.Precision, decimalProperty.Scale.HasValue ? decimalProperty.Scale : 0); } } else if (EdmLibHelpers.HasPrecision(typeKind)) { PrecisionPropertyConfiguration precisionProperty = primitiveProperty as PrecisionPropertyConfiguration; primitiveTypeReference = AddPrecisionConfigInPrimitiveTypeReference( precisionProperty, primitiveTypeReference); } else if (EdmLibHelpers.HasLength(typeKind)) { LengthPropertyConfiguration lengthProperty = primitiveProperty as LengthPropertyConfiguration; primitiveTypeReference = AddLengthConfigInPrimitiveTypeReference( lengthProperty, primitiveTypeReference); } edmProperty = type.AddStructuralProperty( primitiveProperty.Name, primitiveTypeReference, defaultValue: primitiveProperty.DefaultValueString); break; case PropertyKind.Complex: ComplexPropertyConfiguration complexProperty = property as ComplexPropertyConfiguration; IEdmComplexType complexType = GetEdmType(complexProperty.RelatedClrType) as IEdmComplexType; edmProperty = type.AddStructuralProperty( complexProperty.Name, new EdmComplexTypeReference(complexType, complexProperty.OptionalProperty)); break; case PropertyKind.Collection: edmProperty = CreateStructuralTypeCollectionPropertyBody(type, (CollectionPropertyConfiguration)property); break; case PropertyKind.Enum: edmProperty = CreateStructuralTypeEnumPropertyBody(type, (EnumPropertyConfiguration)property); break; default: break; } if (edmProperty != null) { if (property.PropertyInfo != null) { _properties[property.PropertyInfo] = edmProperty; } if (property.IsRestricted) { _propertiesRestrictions[edmProperty] = new QueryableRestrictions(property); } if (property.QueryConfiguration.ModelBoundQuerySettings != null) { _propertiesQuerySettings.Add(edmProperty, property.QueryConfiguration.ModelBoundQuerySettings); } _propertyConfigurations[edmProperty] = property; } } }
private void CreatePrimitiveProperty(PrimitivePropertyConfiguration primitiveProperty, EdmStructuredType type, StructuralTypeConfiguration config, out IEdmProperty edmProperty) { EdmPrimitiveTypeKind typeKind = GetTypeKind(primitiveProperty.PropertyInfo.PropertyType); IEdmTypeReference primitiveTypeReference = EdmCoreModel.Instance.GetPrimitive( typeKind, primitiveProperty.OptionalProperty); // Set concurrency token if is entity type, and concurrency token is true EdmConcurrencyMode concurrencyMode = EdmConcurrencyMode.None; if (config.Kind == EdmTypeKind.Entity && primitiveProperty.ConcurrencyToken) { concurrencyMode = EdmConcurrencyMode.Fixed; } var primitiveProp = new EdmStructuralProperty( type, primitiveProperty.PropertyInfo.Name, primitiveTypeReference, defaultValueString: null, concurrencyMode: concurrencyMode); type.AddProperty(primitiveProp); edmProperty = primitiveProp; // Set Annotation StoreGeneratedPattern if (config.Kind == EdmTypeKind.Entity && primitiveProperty.StoreGeneratedPattern != DatabaseGeneratedOption.None) { _directValueAnnotations.Add( new StoreGeneratedPatternAnnotation(primitiveProp, primitiveProperty.StoreGeneratedPattern)); } }
/// <summary> /// Read an entry-level data property and check its version compliance. /// </summary> /// <param name="entryState">The state of the reader for entry to read.</param> /// <param name="edmProperty">The EDM property of the property being read, or null if the property is an open property.</param> /// <param name="propertyTypeName">The type name specified for the property in property annotation, or null if no such type name is available.</param> /// <remarks> /// Pre-Condition: The reader is positioned on the first node of the property value /// Post-Condition: JsonNodeType.Property: the next property of the entry /// JsonNodeType.EndObject: the end-object node of the entry /// </remarks> private void ReadEntryDataProperty(IODataJsonLightReaderEntryState entryState, IEdmProperty edmProperty, string propertyTypeName) { Debug.Assert(entryState != null, "entryState != null"); Debug.Assert(edmProperty != null, "edmProperty != null"); this.JsonReader.AssertNotBuffering(); // EdmLib bridge marks all key properties as non-nullable, but Astoria allows them to be nullable. // If the property has an annotation to ignore null values, we need to omit the property in requests. ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); object propertyValue = this.ReadNonEntityValue( propertyTypeName, edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default, /*isTopLevelPropertyValue*/ false, /*insideComplexValue*/ false, edmProperty.Name); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { AddEntryProperty(entryState, edmProperty.Name, propertyValue); } this.JsonReader.AssertNotBuffering(); Debug.Assert( this.JsonReader.NodeType == JsonNodeType.Property || this.JsonReader.NodeType == JsonNodeType.EndObject, "Post-Condition: expected JsonNodeType.Property or JsonNodeType.EndObject"); }
private static IEdmProperty CreateAmbiguousPropertyBinding(IEdmProperty first, IEdmProperty second) { var ambiguous = first as AmbiguousPropertyBinding; if (ambiguous != null) { ambiguous.AddBinding(second); return(ambiguous); } return(new AmbiguousPropertyBinding(first.DeclaringType, first, second)); }
/// <summary> /// Validates a named stream property to ensure it's not null and it's name if correct. /// </summary> /// <param name="streamProperty">The stream reference property to validate.</param> /// <param name="edmProperty">Property metadata to validate against.</param> /// <param name="writingResponse">true when writing a response; otherwise false.</param> /// <param name="bypassValidation">Bypass the validation if it is true.</param> /// <remarks>This does NOT validate the value of the stream property, just the property itself.</remarks> internal static void ValidateStreamReferenceProperty(ODataProperty streamProperty, IEdmProperty edmProperty, bool writingResponse, bool bypassValidation = false) { Debug.Assert(streamProperty != null, "streamProperty != null"); if (bypassValidation) { return; } ValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty); if (!writingResponse) { // Stream properties are only valid in responses; writers fail if they encounter them in requests. throw new ODataException(Strings.WriterValidationUtils_StreamPropertyInRequest(streamProperty.Name)); } }
internal static void RegisterProperty(IEdmProperty element, string name, Dictionary <string, IEdmProperty> dictionary) { AddElement(element, name, dictionary, CreateAmbiguousPropertyBinding); }
public static bool IsNotCountable(IEdmProperty edmProperty, IEdmModel edmModel) { QueryableRestrictionsAnnotation annotation = GetPropertyRestrictions(edmProperty, edmModel); return annotation == null ? false : annotation.Restrictions.NotCountable; }
private void SetEpmValueForSegment( EntityPropertyMappingInfo epmInfo, int propertyValuePathIndex, IEdmStructuredTypeReference segmentStructuralTypeReference, ReadOnlyEnumerable <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."); // TODO: Server seems to have a bug where if there's an EPM for an open property where the EPM uses complex types (the source path is deeper than 1) // then it will actually materialize the property as entry level string property, with the value of the deep property value. If there are multiple deep // EPM for the same top-level open property it seems to set the entry level property multiple times with the values as they come from payload. // Client on the other hand doesn't have open properties, and always has a type, so no problem there. if (propertyMetadata == null && propertyValuePathIndex != epmInfo.PropertyValuePath.Length - 1) { throw new ODataException(ODataErrorStrings.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(ODataErrorStrings.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, propertyName); 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, existingComplexValue.Properties.ToReadOnlyEnumerable("Properties"), propertyValue); break; case EdmTypeKind.Collection: Debug.Assert(propertyType.IsNonEntityCollectionType(), "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(ODataErrorStrings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind)); } }
private static QueryableRestrictionsAnnotation GetPropertyRestrictions(IEdmProperty edmProperty, IEdmModel edmModel) { Contract.Assert(edmProperty != null); Contract.Assert(edmModel != null); return edmModel.GetAnnotationValue<QueryableRestrictionsAnnotation>(edmProperty); }
internal Expression CreatePropertyValueExpression(IEdmEntityType elementType, IEdmProperty property, Expression source) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainEntityType, declaringType.FullName())); } source = Expression.TypeAs(source, castType); } Expression propertyValue = Expression.Property(source, property.Name); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : propertyValue propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(null)), ifTrue: Expression.Constant(null, propertyValue.Type.ToNullable()), ifFalse: ExpressionHelpers.ToNullable(propertyValue)); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = ExpressionHelpers.ToNullable(propertyValue); } return(propertyValue); }
private IOrderedQueryable ApplyToCore(IQueryable query, ODataQuerySettings querySettings) { if (_contextElementClrType == null) { throw Error.NotSupported(SRResources.ApplyToOnUntypedQueryOption, "ApplyTo"); } ICollection <OrderByNode> nodes = OrderByNodes; bool alreadyOrdered = false; IQueryable querySoFar = query; HashSet <IEdmProperty> propertiesSoFar = new HashSet <IEdmProperty>(); HashSet <string> openPropertiesSoFar = new HashSet <string>(); bool orderByItSeen = false; foreach (OrderByNode node in nodes) { OrderByPropertyNode propertyNode = node as OrderByPropertyNode; OrderByOpenPropertyNode openPropertyNode = node as OrderByOpenPropertyNode; if (propertyNode != null) { IEdmProperty property = propertyNode.Property; OrderByDirection direction = propertyNode.Direction; // This check prevents queries with duplicate properties (e.g. $orderby=Id,Id,Id,Id...) from causing stack overflows if (propertiesSoFar.Contains(property) && propertiesSoFar.Count > 50) { throw new ODataException(Error.Format(SRResources.OrderByDuplicateProperty, property.Name)); } propertiesSoFar.Add(property); if (propertyNode.OrderByClause != null) { querySoFar = AddOrderByQueryForProperty(query, querySettings, propertyNode.OrderByClause, querySoFar, direction, alreadyOrdered); } else { querySoFar = ExpressionHelpers.OrderByProperty(querySoFar, Context.Model, property, direction, _contextElementClrType, alreadyOrdered); } alreadyOrdered = true; } else if (openPropertyNode != null) { // This check prevents queries with duplicate properties (e.g. $orderby=Id,Id,Id,Id...) from causing stack overflows if (openPropertiesSoFar.Contains(openPropertyNode.PropertyName) && openPropertiesSoFar.Count > 50) { throw new ODataException(Error.Format(SRResources.OrderByDuplicateProperty, openPropertyNode.PropertyName)); } openPropertiesSoFar.Add(openPropertyNode.PropertyName); Contract.Assert(openPropertyNode.OrderByClause != null); querySoFar = AddOrderByQueryForProperty(query, querySettings, openPropertyNode.OrderByClause, querySoFar, openPropertyNode.Direction, alreadyOrdered); alreadyOrdered = true; } else { // This check prevents queries with duplicate nodes (e.g. $orderby=$it,$it,$it,$it...) from causing stack overflows if (orderByItSeen) { throw new ODataException(Error.Format(SRResources.OrderByDuplicateIt)); } querySoFar = ExpressionHelpers.OrderByIt(querySoFar, node.Direction, _contextElementClrType, alreadyOrdered); alreadyOrdered = true; orderByItSeen = true; } } return(querySoFar as IOrderedQueryable); }
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)); }