private static void SnapExpandedEntry(List<DeltaSnapshotEntry> results, object element, IEdmNavigationSource edmParent, IEnumerable<ExpandedNavigationSelectItem> expandedNavigationItems, string parentId) { foreach (var navigationProperty in ((IEdmEntityType)EdmClrTypeUtils.GetEdmType(DataSourceManager.GetCurrentDataSource().Model, element)).NavigationProperties()) { var expandedNavigationItem = GetExpandedNavigationItem(expandedNavigationItems, navigationProperty.Name); if (expandedNavigationItem != null) { bool isCollection = navigationProperty.Type.IsCollection(); ExpandSelectItemHandler expandItemHandler = new ExpandSelectItemHandler(element); expandedNavigationItem.HandleWith(expandItemHandler); var propertyValue = expandItemHandler.ExpandedChildElement; if (propertyValue != null) { IEdmNavigationSource targetSource = edmParent.FindNavigationTarget(navigationProperty); if (isCollection) { SnapResults(results, propertyValue as IEnumerable, targetSource as IEdmEntitySetBase, expandedNavigationItem.SelectAndExpand, parentId, navigationProperty.Name); } else { SnapResult(results, propertyValue, targetSource, expandedNavigationItem.SelectAndExpand, parentId, navigationProperty.Name); } } } } }
private static void SnapResult(List<DeltaSnapshotEntry> results, object entry, IEdmNavigationSource entitySource, SelectExpandClause selectExpandClause, string parentId, string relationShip) { var oDataEntry = ODataObjectModelConverter.ConvertToODataEntry(entry, entitySource, ODataVersion.V4); results.Add(new DeltaSnapshotEntry(oDataEntry.Id.AbsoluteUri, parentId, relationShip)); var expandedNavigationItems = selectExpandClause == null ? null : selectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>(); SnapExpandedEntry(results, entry, entitySource, expandedNavigationItems, oDataEntry.Id.AbsoluteUri); }
/// <summary> /// Writes an OData entry. /// </summary> /// <param name="writer">The ODataWriter that will write the entry.</param> /// <param name="element">The item from the data store to write.</param> /// <param name="navigationSource">The navigation source in the model that the entry belongs to.</param> /// <param name="model">The data store model.</param> /// <param name="targetVersion">The OData version this segment is targeting.</param> /// <param name="selectExpandClause">The SelectExpandClause.</param> public static void WriteEntry(ODataWriter writer, object element, IEdmNavigationSource entitySource, ODataVersion targetVersion, SelectExpandClause selectExpandClause, Dictionary<string, string> incomingHeaders = null) { var entry = ODataObjectModelConverter.ConvertToODataEntry(element, entitySource, targetVersion); entry.ETag = Utility.GetETagValue(element); if (selectExpandClause != null && selectExpandClause.SelectedItems.OfType<PathSelectItem>().Any()) { ExpandSelectItemHandler selectItemHandler = new ExpandSelectItemHandler(entry); foreach (var item in selectExpandClause.SelectedItems.OfType<PathSelectItem>()) { item.HandleWith(selectItemHandler); } entry = selectItemHandler.ProjectedEntry; } CustomizeEntry(incomingHeaders, entry); writer.WriteStart(entry); // gets all of the expandedItems, including ExpandedRefernceSelectItem and ExpandedNavigationItem var expandedItems = selectExpandClause == null ? null : selectExpandClause.SelectedItems.OfType<ExpandedReferenceSelectItem>(); WriteNavigationLinks(writer, element, entry.ReadLink, entitySource, targetVersion, expandedItems); writer.WriteEnd(); }
/// <summary> /// Build a segment representing a navigation property. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <param name="navigationProperty">The navigation property this segment represents.</param> /// <param name="navigationSource">The navigation source of the entities targetted by this navigation property. This can be null.</param> /// <returns>The ODataPath with navigation property appended in the end in the end</returns> public static ODataPath AppendNavigationPropertySegment(this ODataPath path, IEdmNavigationProperty navigationProperty, IEdmNavigationSource navigationSource) { var newPath = new ODataPath(path); NavigationPropertySegment np = new NavigationPropertySegment(navigationProperty, navigationSource); newPath.Add(np); return newPath; }
public static void SnapResults(List<DeltaSnapshotEntry> results, IEnumerable entries, IEdmNavigationSource entitySource, SelectExpandClause selectExpandClause, string parentId, string relationShip) { foreach (object entry in entries) { SnapResult(results, entry, entitySource, selectExpandClause, parentId, relationShip); } }
/// <summary> /// Constructor. /// </summary> /// <param name="outputContext">The output context to write to.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="writingFeed">True if the writer is created for writing a feed; false when it is created for writing an entry.</param> /// <param name="listener">If not null, the writer will notify the implementer of the interface of relevant state changes in the writer.</param> protected ODataWriterCore( ODataOutputContext outputContext, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool writingFeed, IODataReaderWriterListener listener = null) { Debug.Assert(outputContext != null, "outputContext != null"); this.outputContext = outputContext; this.writingFeed = writingFeed; // create a collection validator when writing a top-level feed and a user model is present if (this.writingFeed && this.outputContext.Model.IsUserModel()) { this.feedValidator = new FeedWithoutExpectedTypeValidator(); } if (navigationSource != null && entityType == null) { entityType = this.outputContext.EdmTypeResolver.GetElementType(navigationSource); } ODataUri odataUri = outputContext.MessageWriterSettings.ODataUri.Clone(); // Remove key for top level entry if (!writingFeed && odataUri != null && odataUri.Path != null) { odataUri.Path = odataUri.Path.TrimEndingKeySegment(); } this.listener = listener; this.scopes.Push(new Scope(WriterState.Start, /*item*/null, navigationSource, entityType, /*skipWriting*/false, outputContext.MessageWriterSettings.SelectedProperties, odataUri)); }
/// <summary> /// Constructs a KeyLookupNode. /// </summary> /// <param name="source">The collection that this key is referring to.</param> /// <param name="keyPropertyValues">List of the properties and their values that we use to look up our return value.</param> /// <exception cref="System.ArgumentNullException">Throws if the input source is null.</exception> public KeyLookupNode(EntityCollectionNode source, IEnumerable<KeyPropertyValue> keyPropertyValues) { ExceptionUtils.CheckArgumentNotNull(source, "source"); this.source = source; this.navigationSource = source.NavigationSource; this.entityTypeReference = source.EntityItemType; this.keyPropertyValues = keyPropertyValues; }
/// <summary> /// Initializes a new instance of the <see cref="EdmUnknownEntitySet"/> class. /// </summary> /// <param name="parentNavigationSource">The <see cref="IEdmNavigationSource"/> that container element belongs to</param> /// <param name="navigationProperty">An <see cref="IEdmNavigationProperty"/> containing the navagation property definition of the contained element</param> public EdmUnknownEntitySet(IEdmNavigationSource parentNavigationSource, IEdmNavigationProperty navigationProperty) : base(navigationProperty.Name, navigationProperty.ToEntityType()) { EdmUtil.CheckArgumentNull(parentNavigationSource, "parentNavigationSource"); EdmUtil.CheckArgumentNull(navigationProperty, "navigationProperty"); this.parentNavigationSource = parentNavigationSource; this.navigationProperty = navigationProperty; }
/// <summary> /// Create the Swagger path for the Edm entity. /// </summary> /// <param name="navigationSource">The Edm navigation source.</param> /// <returns>The <see cref="Newtonsoft.Json.Linq.JObject"/> represents the related Edm entity.</returns> public static JObject CreateSwaggerPathForEntity(IEdmNavigationSource navigationSource) { IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; if (entitySet == null) { return new JObject(); } var keyParameters = new JArray(); foreach (var key in entitySet.EntityType().Key()) { string format; string type = GetPrimitiveTypeAndFormat(key.Type.Definition as IEdmPrimitiveType, out format); keyParameters.Parameter(key.Name, "path", "key: " + key.Name, type, format); } return new JObject() { { "get", new JObject() .Summary("Get entity from " + entitySet.Name + " by key.") .OperationId(entitySet.Name + "_GetById") .Description("Returns the entity with the key from " + entitySet.Name) .Tags(entitySet.Name) .Parameters((keyParameters.DeepClone() as JArray) .Parameter("$select", "query", "description", "string")) .Responses(new JObject() .Response("200", "EntitySet " + entitySet.Name, entitySet.EntityType()) .DefaultErrorResponse()) }, { "patch", new JObject() .Summary("Update entity in EntitySet " + entitySet.Name) .OperationId(entitySet.Name + "_PatchById") .Description("Update entity in EntitySet " + entitySet.Name) .Tags(entitySet.Name) .Parameters((keyParameters.DeepClone() as JArray) .Parameter(entitySet.EntityType().Name, "body", "The entity to patch", entitySet.EntityType())) .Responses(new JObject() .Response("204", "Empty response") .DefaultErrorResponse()) }, { "delete", new JObject() .Summary("Delete entity in EntitySet " + entitySet.Name) .OperationId(entitySet.Name + "_DeleteById") .Description("Delete entity in EntitySet " + entitySet.Name) .Tags(entitySet.Name) .Parameters((keyParameters.DeepClone() as JArray) .Parameter("If-Match", "header", "If-Match header", "string")) .Responses(new JObject() .Response("204", "Empty response") .DefaultErrorResponse()) } }; }
/// <summary> /// Build the ExpandOption variant of an SelectExpandBinder /// </summary> /// <param name="configuration">The configuration used for binding.</param> /// <param name="edmType">The type of the top level expand item.</param> /// <param name="navigationSource">The navigation source of the top level expand item.</param> public SelectExpandBinder(ODataUriParserConfiguration configuration, IEdmStructuredType edmType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(edmType, "edmType"); this.configuration = configuration; this.edmType = edmType; this.navigationSource = navigationSource; }
/// <summary> /// Creates a <see cref="EntityRangeVariable"/>. /// </summary> /// <param name="name"> The name of the associated any/all parameter (null if none)</param> /// <param name="entityType">The entity type of each item in the collection that this range variable iterates over.</param> /// <param name="navigationSource">The navigation source of the collection this node iterates over.</param> /// <exception cref="System.ArgumentNullException">Throws if the input name or entityType is null.</exception> public EntityRangeVariable(string name, IEdmEntityTypeReference entityType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(name, "name"); ExceptionUtils.CheckArgumentNotNull(entityType, "entityType"); this.name = name; this.entityTypeReference = entityType; this.entityCollectionNode = null; this.navigationSource = navigationSource; }
/// <inheritdoc/> public override IEdmNavigationSource GetNavigationSource(IEdmNavigationSource previousNavigationSource) { if (NavigationProperty != null && previousNavigationSource != null) { return previousNavigationSource.FindNavigationTarget(NavigationProperty); } return null; }
/// <summary> /// Creates a ParameterQueryNode for an implicit parameter ($it). /// </summary> /// <param name="elementType">Element type the parameter represents.</param> /// <param name="navigationSource">The navigation source. May be null and must be null for non entities.</param> /// <returns>A new IParameterNode.</returns> internal static RangeVariable CreateImplicitRangeVariable(IEdmTypeReference elementType, IEdmNavigationSource navigationSource) { if (elementType.IsEntity()) { return new EntityRangeVariable(ExpressionConstants.It, elementType as IEdmEntityTypeReference, navigationSource); } Debug.Assert(navigationSource == null, "if the type wasn't an entity then there should be no navigation source"); return new NonentityRangeVariable(ExpressionConstants.It, elementType, null); }
/// <summary> /// Handle first level entities, genreate the delta items which need to be write /// </summary> /// <param name="entries">Query results</param> /// <param name="entitySet">EntitySet</param> /// <param name="targetVersion">Target Version</param> /// <param name="selectExpandClause">Select and Expand Clause</param> private void GenerateDeltaItemsFromFeed(IEnumerable entries, IEdmNavigationSource entitySet, ODataVersion targetVersion, SelectExpandClause selectExpandClause) { foreach (var entry in entries) { // Handle single element in first level and their related navigation property GenerateDeltaItemFromEntry(entry, entitySet, targetVersion, selectExpandClause, string.Empty, string.Empty); } // Handle deleted element in first level GenerateDeltaItemsFromDeletedEntities(string.Empty, string.Empty); }
public static void SetNavigationSourceLinkBuilder(this IEdmModel model, IEdmNavigationSource navigationSource, NavigationSourceLinkBuilderAnnotation navigationSourceLinkBuilder) { if (model == null) { throw Error.ArgumentNull("model"); } model.SetAnnotationValue(navigationSource, navigationSourceLinkBuilder); }
/// <summary>Returns the entity type of the given navigation source.</summary> /// <param name="navigationSource">The navigation source to get the element type of.</param> /// <returns>The <see cref="IEdmEntityType"/> representing the entity type of the <paramref name="navigationSource" />.</returns> internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType(); if (entityType == null) { return null; } return (IEdmEntityType)this.ResolveType(entityType); }
/// <summary> /// Constructor creating an OData writer using the ATOM format. /// </summary> /// <param name="atomOutputContext">The output context to write to.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="writingFeed">True if the writer is created for writing a feed; false when it is created for writing an entry.</param> internal ODataAtomWriter( ODataAtomOutputContext atomOutputContext, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool writingFeed) : base(atomOutputContext, navigationSource, entityType, writingFeed) { Debug.Assert(atomOutputContext != null, "atomOutputContext != null"); this.atomOutputContext = atomOutputContext; this.atomEntryAndFeedSerializer = new ODataAtomEntryAndFeedSerializer(this.atomOutputContext); }
/// <summary> /// Constructor for ODataQueryOptionParser /// </summary> /// <param name="model">Model to use for metadata binding.</param> /// <param name="targetEdmType">The target EdmType to apply the query option on.</param> /// <param name="targetNavigationSource">The target navigation source to apply the query option on.</param> /// <param name="queryOptions">The dictionary storing query option key-value pairs.</param> public ODataQueryOptionParser(IEdmModel model, IEdmType targetEdmType, IEdmNavigationSource targetNavigationSource, IDictionary<string, string> queryOptions) { ExceptionUtils.CheckArgumentNotNull(queryOptions, "queryOptions"); this.targetEdmType = targetEdmType; this.targetNavigationSource = targetNavigationSource; this.queryOptions = queryOptions; this.Configuration = new ODataUriParserConfiguration(model) { ParameterAliasValueAccessor = new ParameterAliasValueAccessor(queryOptions.Where(_ => _.Key.StartsWith("@", StringComparison.Ordinal)).ToDictionary(_ => _.Key, _ => _.Value)) }; }
/// <summary> /// Generate delta token and save (delta token, delta query) mapping /// </summary> /// <param name="query">Delta query</param> /// <returns>Delta token</returns> public static string GenerateDeltaToken(Uri query, IEnumerable entries, IEdmNavigationSource entitySource, SelectExpandClause selectExpandClause) { // TODO: Consider multiple threads here, may need add lock here. // May need to optimize here, if $top/$skip/$count //var builder = new ODataAnnotationUriBuilder(baseUri); var deltaSnapshot = new DeltaSnapshot(query); SnapResults(deltaSnapshot.Entries, entries, entitySource, selectExpandClause, string.Empty, string.Empty); string deltaToken = deltaSnapshot.TimeStamp.Ticks.ToString(CultureInfo.InvariantCulture); DeltaTokenDic[deltaToken] = deltaSnapshot; return deltaToken; }
/// <summary> /// Append the key segment in the end of ODataPath, the method does not modify current ODataPath instance, /// it returns a new ODataPath without ending type segment. /// If last segment is type cast, the key would be appended before type cast segment. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <param name="keys">The set of key property names and the values to be used in searching for the given item.</param> /// <param name="edmType">The type of the item this key returns.</param> /// <param name="navigationSource">The navigation source that this key is used to search.</param> /// <returns>The ODataPath with key segment appended</returns> public static ODataPath AppendKeySegment(this ODataPath path, IEnumerable<KeyValuePair<string, object>> keys, IEdmEntityType edmType, IEdmNavigationSource navigationSource) { var handler = new SplitEndingSegmentOfTypeHandler<TypeSegment>(); path.WalkWith(handler); KeySegment keySegment = new KeySegment(keys, edmType, navigationSource); ODataPath newPath = handler.FirstPart; newPath.Add(keySegment); foreach (var segment in handler.LastPart) { newPath.Add(segment); } return newPath; }
/// <summary> /// Initializes a new instance of the <see cref="ODataPath" /> class. /// </summary> /// <param name="segments">The path segments for the path.</param> public ODataPath(IList<ODataPathSegment> segments) { if (segments == null) { throw Error.ArgumentNull("segments"); } foreach (ODataPathSegment segment in segments) { _edmType = segment.GetEdmType(_edmType); _navigationSource = segment.GetNavigationSource(_navigationSource); } _segments = new ReadOnlyCollection<ODataPathSegment>(segments); }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonLightOutputContext">The output context to write to.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="writingFeed">true if the writer is created for writing a feed; false when it is created for writing an entry.</param> /// <param name="writingParameter">true if the writer is created for writing a parameter; false otherwise.</param> /// <param name="listener">If not null, the writer will notify the implementer of the interface of relevant state changes in the writer.</param> internal ODataJsonLightWriter( ODataJsonLightOutputContext jsonLightOutputContext, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool writingFeed, bool writingParameter = false, IODataReaderWriterListener listener = null) : base(jsonLightOutputContext, navigationSource, entityType, writingFeed, listener) { Debug.Assert(jsonLightOutputContext != null, "jsonLightOutputContext != null"); this.jsonLightOutputContext = jsonLightOutputContext; this.jsonLightEntryAndFeedSerializer = new ODataJsonLightEntryAndFeedSerializer(this.jsonLightOutputContext); this.writingParameter = writingParameter; }
/// <summary> /// Constructor. /// </summary> /// <param name="atomInputContext">The input to read the payload from.</param> /// <param name="navigationSource">The navigation source we are going to read entities for.</param> /// <param name="expectedEntityType">The expected entity type for the entry to be read (in case of entry reader) or entries in the feed to be read (in case of feed reader).</param> /// <param name="readingFeed">true if the reader is created for reading a feed; false when it is created for reading an entry.</param> internal ODataAtomReader( ODataAtomInputContext atomInputContext, IEdmNavigationSource navigationSource, IEdmEntityType expectedEntityType, bool readingFeed) : base(atomInputContext, readingFeed, false /*readingDelta*/, null /*listener*/) { Debug.Assert(atomInputContext != null, "atomInputContext != null"); Debug.Assert( expectedEntityType == null || atomInputContext.Model.IsUserModel(), "If the expected type is specified we need model as well. We should have verified that by now."); this.atomInputContext = atomInputContext; this.atomEntryAndFeedDeserializer = new ODataAtomEntryAndFeedDeserializer(atomInputContext); this.EnterScope(new Scope(ODataReaderState.Start, /*item*/ null, navigationSource, expectedEntityType, /*contextUri*/null)); }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonLightOutputContext">The output context to write to.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="writingFeed">true if the writer is created for writing a feed; false when it is created for writing an entry.</param> /// <param name="writingParameter">true if the writer is created for writing a parameter; false otherwise.</param> /// <param name="listener">If not null, the writer will notify the implementer of the interface of relevant state changes in the writer.</param> internal ODataJsonLightWriter( ODataJsonLightOutputContext jsonLightOutputContext, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool writingFeed, bool writingParameter = false, IODataReaderWriterListener listener = null) : base(jsonLightOutputContext, navigationSource, entityType, writingFeed, listener) { Debug.Assert(jsonLightOutputContext != null, "jsonLightOutputContext != null"); this.jsonLightOutputContext = jsonLightOutputContext; this.jsonLightEntryAndFeedSerializer = new ODataJsonLightEntryAndFeedSerializer(this.jsonLightOutputContext); this.writingParameter = writingParameter; this.jsonWriter = this.jsonLightOutputContext.JsonWriter; this.odataAnnotationWriter = new JsonLightODataAnnotationWriter(this.jsonWriter, jsonLightOutputContext.MessageWriterSettings.ODataSimplified); }
/// <summary> /// Initializes a new instance of the <see cref="NavigationSourceLinkBuilderAnnotation"/> class. /// </summary> /// <param name="navigationSource">The navigation source for which the link builder is being constructed.</param> /// <param name="model">The EDM model that this navigation source belongs to.</param> /// <remarks>This constructor creates a link builder that generates URL's that follow OData conventions for the given navigation source.</remarks> public NavigationSourceLinkBuilderAnnotation(IEdmNavigationSource navigationSource, IEdmModel model) { if (navigationSource == null) { throw Error.ArgumentNull("navigationSource"); } if (model == null) { throw Error.ArgumentNull("model"); } IEdmEntityType elementType = navigationSource.EntityType(); IEnumerable<IEdmEntityType> derivedTypes = model.FindAllDerivedTypes(elementType).Cast<IEdmEntityType>(); // Add navigation link builders for all navigation properties of entity. foreach (IEdmNavigationProperty navigationProperty in elementType.NavigationProperties()) { Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory = (entityInstanceContext, navProperty) => entityInstanceContext.GenerateNavigationPropertyLink(navProperty, includeCast: false); AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder(navigationLinkFactory, followsConventions: true)); } // Add navigation link builders for all navigation properties in derived types. bool derivedTypesDefineNavigationProperty = false; foreach (IEdmEntityType derivedEntityType in derivedTypes) { foreach (IEdmNavigationProperty navigationProperty in derivedEntityType.DeclaredNavigationProperties()) { derivedTypesDefineNavigationProperty = true; Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory = (entityInstanceContext, navProperty) => entityInstanceContext.GenerateNavigationPropertyLink(navProperty, includeCast: true); AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder(navigationLinkFactory, followsConventions: true)); } } _navigationSourceName = navigationSource.Name; _feedSelfLinkBuilder = (feedContext) => feedContext.GenerateFeedSelfLink(); Func<EntityInstanceContext, string> selfLinkFactory = (entityInstanceContext) => entityInstanceContext.GenerateSelfLink(includeCast: derivedTypesDefineNavigationProperty); _idLinkBuilder = new SelfLinkBuilder<string>(selfLinkFactory, followsConventions: true); }
/// <inheritdoc/> public override IEdmNavigationSource GetNavigationSource(IEdmNavigationSource previousNavigationSource) { if (_edmModel == null) { return null; } // Try to use the entity set annotation to get the target navigation source. ReturnedEntitySetAnnotation entitySetAnnotation = _edmModel.GetAnnotationValue<ReturnedEntitySetAnnotation>(Action); if (entitySetAnnotation != null) { return _edmModel.EntityContainer.FindEntitySet(entitySetAnnotation.EntitySetName); } // Try to use the entity set path to get the target navigation source. if (previousNavigationSource != null && Action != null) { IEdmOperationParameter parameter; IEnumerable<IEdmNavigationProperty> navigationProperties; IEdmEntityType lastEntityType; IEnumerable<EdmError> errors; if (Action.TryGetRelativeEntitySetPath(_edmModel, out parameter, out navigationProperties, out lastEntityType, out errors)) { IEdmNavigationSource targetNavigationSource = previousNavigationSource; foreach (IEdmNavigationProperty navigationProperty in navigationProperties) { targetNavigationSource = targetNavigationSource.FindNavigationTarget(navigationProperty); if (targetNavigationSource == null) { return null; } } return targetNavigationSource; } } return null; }
public static NavigationSourceLinkBuilderAnnotation GetNavigationSourceLinkBuilder(this IEdmModel model, IEdmNavigationSource navigationSource) { if (model == null) { throw Error.ArgumentNull("model"); } NavigationSourceLinkBuilderAnnotation annotation = model .GetAnnotationValue<NavigationSourceLinkBuilderAnnotation>(navigationSource); if (annotation == null) { // construct and set a navigation source link builder that follows OData URL conventions. annotation = new NavigationSourceLinkBuilderAnnotation(navigationSource, model); model.SetNavigationSourceLinkBuilder(navigationSource, annotation); } return annotation; }
/// <summary> /// Create the Swagger path for the Edm entity set. /// </summary> /// <param name="navigationSource">The Edm navigation source.</param> /// <returns>The <see cref="Newtonsoft.Json.Linq.JObject"/> represents the related Edm entity set.</returns> public static JObject CreateSwaggerPathForEntitySet(IEdmNavigationSource navigationSource) { IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; if (entitySet == null) { return new JObject(); } return new JObject() { { "get", new JObject() .Summary("Get EntitySet " + entitySet.Name) .OperationId(entitySet.Name + "_Get") .Description("Returns the EntitySet " + entitySet.Name) .Tags(entitySet.Name) .Parameters(new JArray() .Parameter("$expand", "query", "Expand navigation property", "string") .Parameter("$select", "query", "select structural property", "string") .Parameter("$orderby", "query", "order by some property", "string") .Parameter("$top", "query", "top elements", "integer") .Parameter("$skip", "query", "skip elements", "integer") .Parameter("$count", "query", "include count in response", "boolean")) .Responses(new JObject() .Response("200", "EntitySet " + entitySet.Name, entitySet.EntityType()) .DefaultErrorResponse()) }, { "post", new JObject() .Summary("Post a new entity to EntitySet " + entitySet.Name) .OperationId(entitySet.Name + "_Post") .Description("Post a new entity to EntitySet " + entitySet.Name) .Tags(entitySet.Name) .Parameters(new JArray() .Parameter(entitySet.EntityType().Name, "body", "The entity to post", entitySet.EntityType())) .Responses(new JObject() .Response("200", "EntitySet " + entitySet.Name, entitySet.EntityType()) .DefaultErrorResponse()) } }; }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonLightInputContext">The input to read the payload from.</param> /// <param name="navigationSource">The navigation source we are going to read entities for.</param> /// <param name="expectedEntityType">The expected entity type for the entry to be read (in case of entry reader) or entries in the feed to be read (in case of feed reader).</param> /// <param name="readingFeed">true if the reader is created for reading a feed; false when it is created for reading an entry.</param> /// <param name="readingParameter">true if the reader is created for reading a parameter; false otherwise.</param> /// <param name="listener">If not null, the Json reader will notify the implementer of the interface of relevant state changes in the Json reader.</param> internal ODataJsonLightReader( ODataJsonLightInputContext jsonLightInputContext, IEdmNavigationSource navigationSource, IEdmEntityType expectedEntityType, bool readingFeed, bool readingParameter = false, IODataReaderWriterListener listener = null) : base(jsonLightInputContext, readingFeed, listener) { Debug.Assert(jsonLightInputContext != null, "jsonLightInputContext != null"); Debug.Assert( expectedEntityType == null || jsonLightInputContext.Model.IsUserModel(), "If the expected type is specified we need model as well. We should have verified that by now."); this.jsonLightInputContext = jsonLightInputContext; this.jsonLightEntryAndFeedDeserializer = new ODataJsonLightEntryAndFeedDeserializer(jsonLightInputContext); this.readingParameter = readingParameter; this.topLevelScope = new JsonLightTopLevelScope(navigationSource, expectedEntityType); this.EnterScope(this.topLevelScope); }
/// <summary> /// Add semantic meaning to a Select or Expand Token /// </summary> /// <param name="elementType">the top level entity type.</param> /// <param name="navigationSource">the top level navigation source</param> /// <param name="expandToken">the syntactically parsed expand token</param> /// <param name="selectToken">the syntactically parsed select token</param> /// <param name="configuration">The configuration to use for parsing.</param> /// <returns>A select expand clause bound to metadata.</returns> public SelectExpandClause Bind( IEdmStructuredType elementType, IEdmNavigationSource navigationSource, ExpandToken expandToken, SelectToken selectToken, ODataUriParserConfiguration configuration) { ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken); ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer(); ExpandToken normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken); SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, elementType, navigationSource); SelectExpandClause clause = selectExpandBinder.Bind(normalizedSelectExpandToken); SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause); new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause); return clause; }
/// <summary> /// Create <see cref="KeySegmentTemplate"/> based on the given entity type and navigation source. /// </summary> /// <param name="entityType">The given entity type.</param> /// <param name="navigationSource">The given navigation source.</param> /// <param name="keyPrefix">The prefix used before key template.</param> /// <returns>The built <see cref="KeySegmentTemplate"/>.</returns> internal static KeySegmentTemplate CreateKeySegment(IEdmEntityType entityType, IEdmNavigationSource navigationSource, string keyPrefix = "key") { if (entityType == null) { throw Error.ArgumentNull(nameof(entityType)); } IDictionary <string, string> keyTemplates = new Dictionary <string, string>(); var keys = entityType.Key().ToArray(); if (keys.Length == 1) { // Id={key} keyTemplates[keys[0].Name] = $"{{{keyPrefix}}}"; } else { // Id1={keyId1},Id2={keyId2} foreach (var key in keys) { keyTemplates[key.Name] = $"{{{keyPrefix}{key.Name}}}"; } } return(new KeySegmentTemplate(keyTemplates, entityType, navigationSource)); }
protected override ODataWriterCore.ResourceScope CreateResourceScope(ODataResource entry, IEdmNavigationSource navigationSource, IEdmStructuredType resourceType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri, bool isUndeclared) { throw new NotImplementedException(); }
/// <summary> /// Creates a new instance of the type annotation for an entity value. /// </summary> /// <param name="navigationSource">The navigation source the entity belongs to (required).</param> /// <param name="entityType">The entity type of the entity value if not the base type of the entity set (optional).</param> public ODataTypeAnnotation(IEdmNavigationSource navigationSource, IEdmEntityType entityType) { ExceptionUtils.CheckArgumentNotNull(entityType, "entityType"); this.navigationSource = navigationSource; this.type = entityType.ToTypeReference(/*isNullable*/ true); }
public static ETag GetETag(this HttpRequestMessage request, EntityTagHeaderValue entityTagHeaderValue) { if (request == null) { throw Error.ArgumentNull("request"); } if (entityTagHeaderValue != null) { if (entityTagHeaderValue.Equals(EntityTagHeaderValue.Any)) { return(new ETag { IsAny = true }); } HttpConfiguration configuration = request.GetConfiguration(); if (configuration == null) { throw Error.InvalidOperation(SRResources.RequestMustContainConfiguration); } // get the etag handler, and parse the etag IDictionary <string, object> properties = configuration.GetETagHandler().ParseETag(entityTagHeaderValue) ?? new Dictionary <string, object>(); IList <object> parsedETagValues = properties.Select(property => property.Value).AsList(); // get property names from request ODataPath odataPath = request.ODataProperties().Path; IEdmModel model = request.GetModel(); IEdmNavigationSource source = odataPath.NavigationSource; if (model != null && source != null) { IList <IEdmStructuralProperty> concurrencyProperties = model.GetConcurrencyProperties(source).ToList(); IList <string> concurrencyPropertyNames = concurrencyProperties.OrderBy(c => c.Name).Select(c => c.Name).AsList(); ETag etag = new ETag(); if (parsedETagValues.Count != concurrencyPropertyNames.Count) { etag.IsWellFormed = false; } IEnumerable <KeyValuePair <string, object> > nameValues = concurrencyPropertyNames.Zip( parsedETagValues, (name, value) => new KeyValuePair <string, object>(name, value)); foreach (var nameValue in nameValues) { IEdmStructuralProperty property = concurrencyProperties.SingleOrDefault(e => e.Name == nameValue.Key); Contract.Assert(property != null); Type clrType = EdmLibHelpers.GetClrType(property.Type, model); Contract.Assert(clrType != null); if (nameValue.Value != null) { Type valueType = nameValue.Value.GetType(); etag[nameValue.Key] = valueType != clrType ? Convert.ChangeType(nameValue.Value, clrType, CultureInfo.InvariantCulture) : nameValue.Value; } else { etag[nameValue.Key] = nameValue.Value; } } return(etag); } } return(null); }
/// <summary> /// Builds an appropriate navigation query node (collection or single) for the given property and parent node. /// </summary> /// <param name="property">Navigation property.</param> /// <param name="parent">Parent Node.</param> /// <param name="namedValues">Named values (key values) that were included in the node we are binding, if any.</param> /// <param name="state">State of binding.</param> /// <param name="keyBinder">Object to perform binding on any key values that are present.</param> /// <param name="navigationSource">The navigation source of the navigation node.</param> /// <returns>A new CollectionNavigationNode or SingleNavigationNode to capture the navigation property access.</returns> internal static QueryNode GetNavigationNode(IEdmNavigationProperty property, SingleResourceNode parent, IEnumerable <NamedValue> namedValues, BindingState state, KeyBinder keyBinder, out IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(property, "property"); ExceptionUtils.CheckArgumentNotNull(parent, "parent"); ExceptionUtils.CheckArgumentNotNull(state, "state"); ExceptionUtils.CheckArgumentNotNull(keyBinder, "keyBinder"); // Handle collection navigation property if (property.TargetMultiplicity() == EdmMultiplicity.Many) { CollectionNavigationNode collectionNavigationNode = new CollectionNavigationNode(parent, property, state.ParsedSegments); navigationSource = collectionNavigationNode.NavigationSource; // Doing key lookup on the collection navigation property if (namedValues != null) { return(keyBinder.BindKeyValues(collectionNavigationNode, namedValues, state.Model)); } // Otherwise it's just a normal collection of entities return(collectionNavigationNode); } Debug.Assert(namedValues == null || !namedValues.Any(), "namedValues should not exist if it isn't a collection"); // Otherwise it's a single navigation property SingleNavigationNode singleNavigationNode = new SingleNavigationNode(parent, property, state.ParsedSegments); navigationSource = singleNavigationNode.NavigationSource; return(singleNavigationNode); }
/// <summary> /// Asynchronously creates an <see cref="ODataReader" /> to read an entry. /// </summary> /// <param name="navigationSource">The navigation source we are going to read entities for.</param> /// <param name="expectedEntityType">The expected entity type for the entry to be read.</param> /// <returns>Task which when completed returns the newly created <see cref="ODataReader"/>.</returns> internal virtual Task <ODataReader> CreateEntryReaderAsync(IEdmNavigationSource navigationSource, IEdmEntityType expectedEntityType) { throw this.CreatePayloadKindNotSupportedException(ODataPayloadKind.Entry); }
// Generates the expression // source => new Wrapper { Instance = source, Container = new PropertyContainer { ..expanded properties.. } } private Expression ProjectElement(Expression source, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmNavigationSource navigationSource) { Contract.Assert(source != null); Type elementType = source.Type; Type wrapperType = typeof(SelectExpandWrapper <>).MakeGenericType(elementType); List <MemberAssignment> wrapperTypeMemberAssignments = new List <MemberAssignment>(); PropertyInfo wrapperProperty; bool isInstancePropertySet = false; bool isTypeNamePropertySet = false; bool isContainerPropertySet = false; // Initialize property 'ModelID' on the wrapper class. // source = new Wrapper { ModelID = 'some-guid-id' } wrapperProperty = wrapperType.GetProperty("ModelID"); wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, Expression.Constant(_modelID))); // Initialize property 'Instance' on the wrapper class // source => new Wrapper { Instance = element } wrapperProperty = wrapperType.GetProperty("Instance"); wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, source)); if (IsSelectAll(selectExpandClause)) { wrapperProperty = wrapperType.GetProperty("UseInstanceForProperties"); wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, Expression.Constant(true))); isInstancePropertySet = true; } else { // Initialize property 'TypeName' on the wrapper class as we don't have the instance. Expression typeName = CreateTypeNameExpression(source, entityType, _model); if (typeName != null) { isTypeNamePropertySet = true; } } // Initialize the property 'Container' on the wrapper class // source => new Wrapper { Container = new PropertyContainer { .... } } if (selectExpandClause != null) { Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand = GetPropertiesToExpandInQuery(selectExpandClause); ISet <IEdmStructuralProperty> autoSelectedProperties; ISet <IEdmStructuralProperty> propertiesToInclude = GetPropertiesToIncludeInQuery(selectExpandClause, entityType, navigationSource, _model, out autoSelectedProperties); bool isSelectingOpenTypeSegments = GetSelectsOpenTypeSegments(selectExpandClause, entityType); if (propertiesToExpand.Count > 0 || propertiesToInclude.Count > 0 || autoSelectedProperties.Count > 0) { wrapperProperty = wrapperType.GetProperty("Container"); Contract.Assert(wrapperProperty != null); Expression propertyContainerCreation = BuildPropertyContainer(entityType, source, propertiesToExpand, propertiesToInclude, autoSelectedProperties, isSelectingOpenTypeSegments); wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, propertyContainerCreation)); isContainerPropertySet = true; } } Type wrapperGenericType = GetWrapperGenericType(isInstancePropertySet, isTypeNamePropertySet, isContainerPropertySet); wrapperType = wrapperGenericType.MakeGenericType(elementType); return(Expression.MemberInit(Expression.New(wrapperType), wrapperTypeMemberAssignments)); }
/// <summary> /// Initializes a new instance of the <see cref="KeySegmentTemplate" /> class. /// </summary> /// <param name="keys">The input key mappings, the key string is case-sensitive, the value string should wrapper with { and }.</param> /// <param name="entityType">The declaring type containes the key.</param> /// <param name="navigationSource">The navigation source. It could be null.</param> public KeySegmentTemplate(IDictionary <string, string> keys, IEdmEntityType entityType, IEdmNavigationSource navigationSource) { if (keys == null) { throw Error.ArgumentNull(nameof(keys)); } EntityType = entityType ?? throw Error.ArgumentNull(nameof(entityType)); NavigationSource = navigationSource; KeyMappings = BuildKeyMappings(keys.Select(kvp => new KeyValuePair <string, object>(kvp.Key, kvp.Value)), entityType); Literal = KeyMappings.Count == 1 ? $"{{{KeyMappings.First().Value}}}" : string.Join(",", KeyMappings.Select(a => $"{a.Key}={{{a.Value}}}")); }
private void WriteToStream(Type type, object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders) { IEdmModel model = Request.ODataProperties().Model; if (model == null) { throw Error.InvalidOperation(SRResources.RequestMustHaveModel); } ODataSerializer serializer = GetSerializer(type, value, model, _serializerProvider); UrlHelper urlHelper = Request.GetUrlHelper() ?? new UrlHelper(Request); ODataPath path = Request.ODataProperties().Path; IEdmNavigationSource targetNavigationSource = path == null ? null : path.NavigationSource; // serialize a response HttpConfiguration configuration = Request.GetConfiguration(); if (configuration == null) { throw Error.InvalidOperation(SRResources.RequestMustContainConfiguration); } string preferHeader = RequestPreferenceHelpers.GetRequestPreferHeader(Request); string annotationFilter = null; if (!String.IsNullOrEmpty(preferHeader)) { ODataMessageWrapper messageWrapper = new ODataMessageWrapper(writeStream, content.Headers); messageWrapper.SetHeader(RequestPreferenceHelpers.PreferHeaderName, preferHeader); annotationFilter = messageWrapper.PreferHeader().AnnotationFilter; } IODataResponseMessage responseMessage = new ODataMessageWrapper(writeStream, content.Headers); if (annotationFilter != null) { responseMessage.PreferenceAppliedHeader().AnnotationFilter = annotationFilter; } Uri baseAddress = GetBaseAddress(Request); ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings(MessageWriterSettings) { PayloadBaseUri = baseAddress, Version = _version, }; string metadataLink = urlHelper.CreateODataLink(new MetadataPathSegment()); if (metadataLink == null) { throw new SerializationException(SRResources.UnableToDetermineMetadataUrl); } writerSettings.ODataUri = new ODataUri { ServiceRoot = baseAddress, // TODO: 1604 Convert webapi.odata's ODataPath to ODL's ODataPath, or use ODL's ODataPath. SelectAndExpand = Request.ODataProperties().SelectExpandClause, Path = (path == null || IsOperationPath(path)) ? null : path.ODLPath, }; MediaTypeHeaderValue contentType = null; if (contentHeaders != null && contentHeaders.ContentType != null) { contentType = contentHeaders.ContentType; } using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, writerSettings, model)) { ODataSerializerContext writeContext = new ODataSerializerContext() { Request = Request, RequestContext = Request.GetRequestContext(), Url = urlHelper, NavigationSource = targetNavigationSource, Model = model, RootElementName = GetRootElementName(path) ?? "root", SkipExpensiveAvailabilityChecks = serializer.ODataPayloadKind == ODataPayloadKind.Feed, Path = path, MetadataLevel = ODataMediaTypes.GetMetadataLevel(contentType), SelectExpandClause = Request.ODataProperties().SelectExpandClause }; serializer.WriteObject(value, type, messageWriter, writeContext); } }
internal static IEdmEntitySetBase GetTargetEntitySet(this IEdmOperation operation, IEdmNavigationSource source, IEdmModel model) { if (source == null) { return(null); } if (operation.IsBound && operation.Parameters.Any()) { IEdmOperationParameter parameter; Dictionary <IEdmNavigationProperty, IEdmPathExpression> path; IEdmEntityType lastEntityType; IEnumerable <EdmError> errors; if (operation.TryGetRelativeEntitySetPath(model, out parameter, out path, out lastEntityType, out errors)) { IEdmNavigationSource target = source; foreach (var navigation in path) { target = target.FindNavigationTarget(navigation.Key, navigation.Value); } return(target as IEdmEntitySetBase); } } return(null); }
/// <summary> /// Initializes a new instance of the <see cref="FunctionSegmentTemplate" /> class. /// </summary> /// <param name="function">The Edm function, it should be bound function.</param> /// <param name="navigationSource">The Edm navigation source of this function return. It could be null.</param> public FunctionSegmentTemplate(IEdmFunction function, IEdmNavigationSource navigationSource) : this(function.GetFunctionParamterMappings(), function, navigationSource) { }
/// <summary> /// Returns the entity type of the given navigation source. /// </summary> /// <param name="navigationSource">The navigation source to get the entity type of.</param> /// <returns>The <see cref="IEdmEntityType"/> representing the entity type of the <paramref name="navigationSource" />.</returns> internal abstract IEdmEntityType GetElementType(IEdmNavigationSource navigationSource);
/// <summary> /// Initializes a new instance of the <see cref="FunctionSegmentTemplate" /> class. /// </summary> /// <param name="parameters">The function parameter template mappings.The key string is case-sensitive, the value string should wrapper with { and }.</param> /// <param name="function">The Edm function, it should be bound function.</param> /// <param name="navigationSource">The Edm navigation source of this function return. It could be null.</param> public FunctionSegmentTemplate(IDictionary <string, string> parameters, IEdmFunction function, IEdmNavigationSource navigationSource) { if (parameters == null) { throw Error.ArgumentNull(nameof(parameters)); } Function = function ?? throw Error.ArgumentNull(nameof(function)); NavigationSource = navigationSource; // Only accept the bound function if (!function.IsBound) { throw new ODataException(Error.Format(SRResources.OperationIsNotBound, function.Name, "function")); } // Parameters should include all required parameter, but maybe include the optional parameter. ParameterMappings = function.VerifyAndBuildParameterMappings(parameters); }
// new CollectionWrapper<ElementType> { Instance = source.Select((ElementType element) => new Wrapper { }) } private Expression ProjectCollection(Expression source, Type elementType, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmNavigationSource navigationSource, ExpandedNavigationSelectItem expandedItem, int?modelBoundPageSize) { ParameterExpression element = Expression.Parameter(elementType); // expression // new Wrapper { } Expression projection = ProjectElement(element, selectExpandClause, entityType, navigationSource); // expression // (ElementType element) => new Wrapper { } LambdaExpression selector = Expression.Lambda(projection, element); if (expandedItem != null) { source = AddOrderByQueryForSource(source, expandedItem.OrderByOption, elementType); } if (_settings.PageSize.HasValue || modelBoundPageSize.HasValue || (expandedItem != null && (expandedItem.TopOption.HasValue || expandedItem.SkipOption.HasValue))) { // nested paging. Need to apply order by first, and take one more than page size as we need to know // whether the collection was truncated or not while generating next page links. IEnumerable <IEdmStructuralProperty> properties = entityType.Key().Any() ? entityType.Key() : entityType .StructuralProperties() .Where(property => property.Type.IsPrimitive() && !property.Type.IsStream()) .OrderBy(property => property.Name); if (expandedItem == null || expandedItem.OrderByOption == null) { bool alreadyOrdered = false; foreach (var prop in properties) { source = ExpressionHelpers.OrderByPropertyExpression(source, prop.Name, elementType, alreadyOrdered); if (!alreadyOrdered) { alreadyOrdered = true; } } } if (expandedItem != null && expandedItem.SkipOption.HasValue) { Contract.Assert(expandedItem.SkipOption.Value <= Int32.MaxValue); source = ExpressionHelpers.Skip(source, (int)expandedItem.SkipOption.Value, elementType, _settings.EnableConstantParameterization); } if (expandedItem != null && expandedItem.TopOption.HasValue) { Contract.Assert(expandedItem.TopOption.Value <= Int32.MaxValue); source = ExpressionHelpers.Take(source, (int)expandedItem.TopOption.Value, elementType, _settings.EnableConstantParameterization); } if (_settings.PageSize.HasValue) { source = ExpressionHelpers.Take(source, _settings.PageSize.Value + 1, elementType, _settings.EnableConstantParameterization); } else if (_settings.ModelBoundPageSize.HasValue) { source = ExpressionHelpers.Take(source, modelBoundPageSize.Value + 1, elementType, _settings.EnableConstantParameterization); } } // expression // source.Select((ElementType element) => new Wrapper { }) Expression selectedExpresion = Expression.Call(GetSelectMethod(elementType, projection.Type), source, selector); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : projectedCollection return(Expression.Condition( test: Expression.Equal(source, Expression.Constant(null)), ifTrue: Expression.Constant(null, selectedExpresion.Type), ifFalse: selectedExpresion)); } else { return(selectedExpresion); } }
/// <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)); }
private void GetAutoSelectExpandItems( IEdmEntityType baseEntityType, IEdmModel model, IEdmNavigationSource navigationSource, bool isAllSelected, ModelBoundQuerySettings modelBoundQuerySettings, int depth, out List <SelectItem> autoSelectItems, out List <SelectItem> autoExpandItems) { autoSelectItems = new List <SelectItem>(); autoExpandItems = new List <SelectItem>(); var autoSelectProperties = EdmHelpers.GetAutoSelectProperties(null, baseEntityType, model, modelBoundQuerySettings); foreach (var autoSelectProperty in autoSelectProperties) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new PropertySegment(autoSelectProperty) }; PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); autoSelectItems.Add(pathSelectItem); } depth--; if (depth < 0) { return; } var autoExpandNavigationProperties = EdmHelpers.GetAutoExpandNavigationProperties(null, baseEntityType, model, !isAllSelected, modelBoundQuerySettings); foreach (var navigationProperty in autoExpandNavigationProperties) { IEdmNavigationSource currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty); if (currentEdmNavigationSource != null) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new NavigationPropertySegment(navigationProperty, currentEdmNavigationSource) }; ODataExpandPath expandPath = new ODataExpandPath(pathSegments); SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(), true); ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); modelBoundQuerySettings = EdmHelpers.GetModelBoundQuerySettings(navigationProperty, navigationProperty.ToEntityType(), model); List <SelectItem> nestedSelectItems; List <SelectItem> nestedExpandItems; int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name); if (maxExpandDepth != 0 && maxExpandDepth < depth) { depth = maxExpandDepth; } GetAutoSelectExpandItems( currentEdmNavigationSource.EntityType(), model, item.NavigationSource, true, modelBoundQuerySettings, depth, out nestedSelectItems, out nestedExpandItems); selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems), nestedSelectItems.Count == 0); item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); autoExpandItems.Add(item); if (!isAllSelected || autoSelectProperties.Any()) { PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); autoExpandItems.Add(pathSelectItem); } } } }
/// <summary> /// Creates a ParameterQueryNode for an implicit parameter ($it). /// </summary> /// <param name="elementType">Element type the parameter represents.</param> /// <param name="navigationSource">The navigation source. May be null and must be null for non entities.</param> /// <returns>A new IParameterNode.</returns> internal static RangeVariable CreateImplicitRangeVariable(IEdmTypeReference elementType, IEdmNavigationSource navigationSource) { if (elementType.IsEntity()) { return(new EntityRangeVariable(ExpressionConstants.It, elementType as IEdmEntityTypeReference, navigationSource)); } Debug.Assert(navigationSource == null, "if the type wasn't an entity then there should be no navigation source"); return(new NonentityRangeVariable(ExpressionConstants.It, elementType, null)); }
/// <inheritdoc/> public override IEdmNavigationSource GetNavigationSource(IEdmNavigationSource previousNavigationSource) { return(previousNavigationSource); }
/// <summary> /// Constructor creating a new reader scope. /// </summary> /// <param name="state">The reader state of this scope.</param> /// <param name="item">The item attached to this scope.</param> /// <param name="navigationSource">The navigation source we are going to read entities for.</param> /// <param name="expectedResourceType">The expected resource type for the scope.</param> /// <param name="odataUri">The odataUri parsed based on the context uri for current scope</param> internal StreamScope(ODataReaderState state, ODataItem item, IEdmNavigationSource navigationSource, IEdmTypeReference expectedResourceType, ODataUri odataUri) : base(state, item, navigationSource, expectedResourceType, odataUri) { this.StreamingState = StreamingState.None; }
/// <summary> /// Helper for translating an access to a metadata-defined property or navigation. /// </summary> /// <param name="sourceNode">The source of the property access.</param> /// <param name="edmPropertyName">The structural or navigation property being accessed.</param> /// <param name="navigationSource">The navigation source of the result, required for navigations.</param> /// <returns>The translated string.</returns> private string TranslatePropertyAccess(QueryNode sourceNode, string edmPropertyName, IEdmNavigationSource navigationSource = null) { string source = this.TranslateNode(sourceNode); if (string.IsNullOrEmpty(source)) { return(this.QueryFormatter.TranslateFieldName(edmPropertyName)); } else { return(this.QueryFormatter.TranslateSource(source, edmPropertyName)); } }
internal Scope(ODataReaderState state, ODataItem item, IEdmNavigationSource navigationSource, IEdmTypeReference expectedResourceTypeReference, ODataUri odataUri) : this(state, item, odataUri) { this.NavigationSource = navigationSource; this.ResourceTypeReference = expectedResourceTypeReference; }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonLightOutputContext">The output context to write to.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the resource set to be written (or null if the entity set base type should be used).</param> public ODataJsonLightDeltaWriter(ODataJsonLightOutputContext jsonLightOutputContext, IEdmNavigationSource navigationSource, IEdmEntityType entityType) { Debug.Assert(jsonLightOutputContext != null, "jsonLightOutputContext != null"); this.navigationSource = navigationSource; this.entityType = entityType; this.jsonLightOutputContext = jsonLightOutputContext; this.resourceWriter = new ODataJsonLightWriter(jsonLightOutputContext, navigationSource, entityType, true, writingDelta: true); this.inStreamErrorListener = resourceWriter; }
/// <summary> /// Append the key segment in the end of ODataPath, the method does not modify current ODataPath instance, /// it returns a new ODataPath without ending type segment. /// If last segment is type cast, the key would be appended before type cast segment. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <param name="keys">The set of key property names and the values to be used in searching for the given item.</param> /// <param name="edmType">The type of the item this key returns.</param> /// <param name="navigationSource">The navigation source that this key is used to search.</param> /// <returns>The ODataPath with key segment appended</returns> public static ODataPath AppendKeySegment(this ODataPath path, IEnumerable <KeyValuePair <string, object> > keys, IEdmEntityType edmType, IEdmNavigationSource navigationSource) { var handler = new SplitEndingSegmentOfTypeHandler <TypeSegment>(); path.WalkWith(handler); KeySegment keySegment = new KeySegment(keys, edmType, navigationSource); ODataPath newPath = handler.FirstPart; newPath.Add(keySegment); foreach (var segment in handler.LastPart) { newPath.Add(segment); } return(newPath); }
/// <summary> /// Gets the <see cref="NavigationSourceLinkBuilderAnnotation"/> to be used while generating self and navigation /// links for the given navigation source. /// </summary> /// <param name="model">The <see cref="IEdmModel"/> containing the navigation source.</param> /// <param name="navigationSource">The navigation source.</param> /// <returns>The <see cref="NavigationSourceLinkBuilderAnnotation"/> if set for the given the singleton; otherwise, /// a new <see cref="NavigationSourceLinkBuilderAnnotation"/> that generates URLs that follow OData URL conventions. /// </returns> public static NavigationSourceLinkBuilderAnnotation GetNavigationSourceLinkBuilder(this IEdmModel model, IEdmNavigationSource navigationSource) { if (model == null) { throw Error.ArgumentNull("model"); } NavigationSourceLinkBuilderAnnotation annotation = model .GetAnnotationValue <NavigationSourceLinkBuilderAnnotation>(navigationSource); if (annotation == null) { // construct and set a navigation source link builder that follows OData URL conventions. annotation = new NavigationSourceLinkBuilderAnnotation(navigationSource, model); model.SetNavigationSourceLinkBuilder(navigationSource, annotation); } return(annotation); }
/// <summary> /// Build a segment representing a navigation property. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <param name="navigationProperty">The navigation property this segment represents.</param> /// <param name="navigationSource">The navigation source of the entities targeted by this navigation property. This can be null.</param> /// <returns>The ODataPath with navigation property segment appended in the end.</returns> public static ODataPath AppendNavigationPropertySegment(this ODataPath path, IEdmNavigationProperty navigationProperty, IEdmNavigationSource navigationSource) { var newPath = new ODataPath(path); NavigationPropertySegment np = new NavigationPropertySegment(navigationProperty, navigationSource); newPath.Add(np); return(newPath); }
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; }
/// <summary> /// Constructor for ODataQueryOptionParser /// </summary> /// <param name="model">Model to use for metadata binding.</param> /// <param name="targetEdmType">The target EdmType to apply the query option on.</param> /// <param name="targetNavigationSource">The target navigation source to apply the query option on.</param> /// <param name="queryOptions">The dictionary storing query option key-value pairs.</param> public ODataQueryOptionParser(IEdmModel model, IEdmType targetEdmType, IEdmNavigationSource targetNavigationSource, IDictionary <string, string> queryOptions) : this(model, targetEdmType, targetNavigationSource, queryOptions, null) { }
public override ODataWriter CreateODataResourceWriter(IEdmNavigationSource navigationSource, IEdmStructuredType resourceType) { return(new ODataAvroWriter(this, value => this.AvroWriter.Write(value), this.AvroWriter.UpdateSchema(null, resourceType), false)); }
/// <summary> /// Adds a navigation target, specifying the destination entity set of a navigation property of an entity in this navigation source. /// </summary> /// <param name="property">The navigation property the target is being set for.</param> /// <param name="target">The destination navigation source of the specified navigation property.</param> public void AddNavigationTarget(IEdmNavigationProperty property, IEdmNavigationSource target) { this.navigationPropertyMappings[property] = target; this.navigationTargetsCache.Clear(null); }