public void CreateNamedPropertyExpression_NonDerivedProperty_ReturnsMemberAccessExpression(HandleNullPropagationOption options) { SelectExpandBinder binder = GetBinder <Customer>(_model, options); Expression customer = Expression.Constant(new Customer()); IEdmStructuralProperty homeAddressProperty = _customer.StructuralProperties().Single(c => c.Name == "HomeLocation"); ODataSelectPath selectPath = new ODataSelectPath(new PropertySegment(homeAddressProperty)); PathSelectItem pathSelectItem = new PathSelectItem(selectPath); NamedPropertyExpression namedProperty = binder.CreateNamedPropertyExpression(customer, _customer, pathSelectItem); Assert.NotNull(namedProperty); Assert.Equal("\"HomeLocation\"", namedProperty.Name.ToString()); if (options != HandleNullPropagationOption.True) { Assert.Equal("value(NS.Customer).HomeLocation", namedProperty.Value.ToString()); } else { Assert.Equal("IIF((value(NS.Customer) == null)," + " null," + " value(NS.Customer).HomeLocation)", namedProperty.Value.ToString()); } }
internal static SelectedPropertiesNode IncludeEntireSubtree(this SelectedPropertiesNode node, IEdmEntityType entityType) { var expected = entityType.StructuralProperties().Where(p => p.Type.IsStream()); var edmStructuralProperties = node.GetSelectedStreamProperties(entityType).Values; Assert.Equal(expected.Count(), edmStructuralProperties.Count); foreach (var prop in edmStructuralProperties) { Assert.Contains(prop, expected); } var navExpected = entityType.NavigationProperties(); var edmNavProperties = node.GetSelectedNavigationProperties(entityType); Assert.Equal(navExpected.Count(), edmNavProperties.Count()); foreach (var prop in edmNavProperties) { Assert.Contains(prop, navExpected); } foreach (var navigation in entityType.NavigationProperties()) { node.GetSelectedPropertiesForNavigationProperty(entityType, navigation.Name).HaveEntireSubtree(); } return(node); }
/// <summary> /// Retrieves the paths for a media entity stream. /// </summary> /// <param name="entityType">The entity type.</param> /// <param name="currentPath">The current OData path.</param> private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath currentPath) { Debug.Assert(entityType != null); Debug.Assert(currentPath != null); bool createValuePath = true; foreach (IEdmStructuralProperty sp in entityType.StructuralProperties()) { if (sp.Type.AsPrimitive().IsStream()) { currentPath.Push(new ODataStreamPropertySegment(sp.Name)); AppendPath(currentPath.Clone()); currentPath.Pop(); } if (sp.Name.Equals("content", StringComparison.OrdinalIgnoreCase)) { createValuePath = false; } } /* Create a /$value path only if entity has stream and * does not contain a structural property named Content */ if (createValuePath && entityType.HasStream) { currentPath.Push(new ODataStreamContentSegment()); AppendPath(currentPath.Clone()); currentPath.Pop(); } }
public EdmDeltaModel(IEdmModel source, IEdmEntityType entityType, IEnumerable <string> propertyNames) { _source = source; _entityType = new EdmEntityType(entityType.Namespace, entityType.Name); foreach (var property in entityType.StructuralProperties()) { if (propertyNames.Contains(property.Name)) { _entityType.AddStructuralProperty(property.Name, property.Type, property.DefaultValueString, property.ConcurrencyMode); } } foreach (var property in entityType.NavigationProperties()) { if (propertyNames.Contains(property.Name)) { var navInfo = new EdmNavigationPropertyInfo() { ContainsTarget = property.ContainsTarget, DependentProperties = property.DependentProperties(), Name = property.Name, OnDelete = property.OnDelete, Target = property.Partner != null ? property.Partner.DeclaringEntityType() : property.Type.TypeKind() == EdmTypeKind.Collection ? (property.Type.Definition as IEdmCollectionType).ElementType.Definition as IEdmEntityType : null, TargetMultiplicity = property.TargetMultiplicity(), }; _entityType.AddUnidirectionalNavigation(navInfo); } } }
public void CreateNamedPropertyExpression_WithDerivedProperty_ReturnsMemberAccessExpression(HandleNullPropagationOption options) { SelectExpandBinder binder = GetBinder <Customer>(_model, options); //Expression customer = Expression.Parameter(typeof(Customer)); output will be different. Expression customer = Expression.Constant(new Customer()); IEdmStructuralProperty vipAddressProperty = _vipCustomer.StructuralProperties().Single(c => c.Name == "VipAddress"); ODataSelectPath selectPath = new ODataSelectPath(new TypeSegment(_vipCustomer, _customer, null), new PropertySegment(vipAddressProperty)); PathSelectItem pathSelectItem = new PathSelectItem(selectPath); NamedPropertyExpression namedProperty = binder.CreateNamedPropertyExpression(customer, _customer, pathSelectItem); Assert.NotNull(namedProperty); Assert.Equal("\"VipAddress\"", namedProperty.Name.ToString()); if (options != HandleNullPropagationOption.True) { Assert.Equal("(value(NS.Customer) As VipCustomer).VipAddress", namedProperty.Value.ToString()); } else { Assert.Equal("IIF(((value(NS.Customer) As VipCustomer) == null)," + " null," + " (value(NS.Customer) As VipCustomer).VipAddress)", namedProperty.Value.ToString()); } }
public void EntityType_reference_extensions() { IEdmModel edmModel = this.GetEdmModel(); IEdmEntityType derivedEntityType = edmModel.SchemaElements.OfType <IEdmEntityType>().First(c => c.BaseType != null); IEdmEntityType baseEntityType = derivedEntityType.BaseEntityType(); Assert.IsNotNull(baseEntityType, "Base entity type should not be null!"); IEdmEntityTypeReference derivedEntityTypeRef = (IEdmEntityTypeReference)derivedEntityType.ToTypeReference(); Assert.AreEqual(baseEntityType, derivedEntityTypeRef.BaseEntityType(), "EntityTypeReference.BaseEntityType()"); Assert.AreEqual(baseEntityType, derivedEntityTypeRef.BaseType(), "EntityTypeReference.BaseType()"); Assert.AreEqual(derivedEntityType.IsAbstract, derivedEntityTypeRef.IsAbstract(), "StructuralTypeReference.IsAbstract()"); Assert.AreEqual(derivedEntityType.IsOpen, derivedEntityTypeRef.IsOpen(), "StructuralTypeReference.IsOpen()"); Assert.AreEqual(derivedEntityType.DeclaredStructuralProperties().Count(), derivedEntityTypeRef.DeclaredStructuralProperties().Count(), "StructuralTypeReference.DeclaredStructuralProperties()"); Assert.AreEqual(derivedEntityType.StructuralProperties().Count(), derivedEntityTypeRef.StructuralProperties().Count(), "StructuralTypeReference.StructuralProperties()"); Assert.AreEqual(derivedEntityType.DeclaredNavigationProperties().Count(), derivedEntityTypeRef.DeclaredNavigationProperties().Count(), "EntityTypeReference.DeclaredNavigationProperties()"); Assert.AreEqual(derivedEntityType.NavigationProperties().Count(), derivedEntityTypeRef.NavigationProperties().Count(), "EntityTypeReference.NavigationProperties()"); IEdmNavigationProperty result = derivedEntityTypeRef.FindNavigationProperty("_Not_Exist_"); Assert.IsNull(result, "Should not find Navigation Property {0}", "_Not_Exist_"); var navigation = derivedEntityType.NavigationProperties().First(); result = derivedEntityTypeRef.FindNavigationProperty(navigation.Name); Assert.AreEqual(navigation, result, "FindNavigationProperty({0})", navigation.Name); }
static OrderBySetting FindProperties(IEdmEntityType entity) { var propertyNames = entity.Key().Any() switch { true => entity.Key().Select(k => k.Name), false => entity.StructuralProperties() .Where(p => p.Type.IsPrimitive() && !p.Type.IsStream()) .Select(p => p.Name) .OrderBy(n => n) .Take(1) }; var orderBySettings = new OrderBySetting(); propertyNames.Aggregate(orderBySettings, (settings, name) => { if (settings.Name is null) { settings.Name = name; return(settings); } settings.ThenBy = new() { Name = name }; return(settings.ThenBy); }); return(orderBySettings.Name is null ? null : orderBySettings); } } }
/// <summary> /// Create entity class from EDMX entity definition. /// </summary> /// <param name="entityType">entity type from CSDL</param> /// <returns>class defination string</returns> /// <remarks> /// References /// - http://roslynquoter.azurewebsites.net/ /// - https://gist.github.com/cmendible/9b8c7d7598f1ab0bc7ab5d24b2622622 /// - https://joshvarty.com/2015/09/18/learn-roslyn-now-part-13-keeping-track-of-syntax-nodes-with-syntax-annotations/ /// </remarks> public static CompilationUnitSyntax From(IEdmEntityType entityType) { var name = entityType.Name; // [Table("Foo")] // public class Foo { } var @class = ClassDeclaration(name) .AddModifiers(PublicModifier()) .AddAttribute(Attribute("Table", name)); foreach (var structuralProp in entityType.StructuralProperties()) { @class = @class.AddMembers(GetPropertyDeclarationSyntax(structuralProp)); } foreach (var navigationProp in entityType.NavigationProperties()) { @class = @class.AddMembers(GetPropertyDeclarationSyntax(navigationProp)); } // namespace SampleModel { } var @namespace = NamespaceDeclaration(entityType.Namespace) .AddMembers(@class); // using System; var root = CompilationUnit() .AddUsings("System", "System.Collections.Generic", "System.ComponentModel.DataAnnotations", "System.ComponentModel.DataAnnotations.Schema") .AddMembers(@namespace); return(root); }
/// <summary> /// Converts an item from the data store into an ODataEntry. /// </summary> /// <param name="element">The item to convert.</param> /// <param name="entitySet">The entity set that the item belongs to.</param> /// <param name="targetVersion">The OData version this segment is targeting.</param> /// <returns>The converted ODataEntry.</returns> public static ODataEntry ConvertToODataEntry(object element, IEdmEntitySet entitySet, ODataVersion targetVersion) { IEdmEntityType entityType = entitySet.EntityType(); Uri entryUri = BuildEntryUri(element, entitySet, targetVersion); var entry = new ODataEntry { // writes out the edit link including the service base uri , e.g.: http://<serviceBase>/Customers('ALFKI') EditLink = entryUri, // writes out the self link including the service base uri , e.g.: http://<serviceBase>/Customers('ALFKI') ReadLink = entryUri, // we use the EditLink as the Id for this entity to maintain convention, Id = entryUri, // writes out the <category term='Customer'/> element TypeName = element.GetType().Namespace + "." + entityType.Name, Properties = entityType.StructuralProperties().Select(p => ConvertToODataProperty(element, p.Name)), }; return(entry); }
private static string GenerateDefaultOrderBy(ODataQueryContext context) { Contract.Assert(context != null && context.EntitySet != null); IEdmEntityType entityType = context.EntitySet.ElementType; // choose the keys alphabetically. This would return a stable sort. string sortOrder = String.Join(",", entityType .Key() .OrderBy(property => property.Name) .Select(property => property.Name)); if (String.IsNullOrEmpty(sortOrder)) { // If there are no keys, choose the primitive properties alphabetically. This // might not result in a stable sort especially if there are duplicates and is only // a best effort solution. sortOrder = String.Join(",", entityType .StructuralProperties() .Where(property => property.Type.IsPrimitive()) .OrderBy(property => property.Name) .Select(property => property.Name)); } return(sortOrder); }
public void Index([FromBody] ODataUntypedActionParameters parameters) { IEdmModel model = Request.ODataProperties().Model; IEdmEntityTypeReference docTypeRef = model.GetDocTypeRef(); IEdmEntityType docType = docTypeRef.EntityDefinition(); IEdmEntityObject CopyDocument(IEdmComplexObject source) { var target = new EdmEntityObject(docTypeRef); foreach (string propertyName in docType.StructuralProperties().Select(p => p.Name)) { if (source.TryGetPropertyValue(propertyName, out object propertyValue)) { target.TrySetPropertyValue(propertyName, propertyValue); } } return(target); } var documentsObjects = (EdmComplexObjectCollection)parameters["value"]; IEnumerable <IEdmEntityObject> documents = documentsObjects.Select(CopyDocument); Documents.AddRange(documents); }
public EdmDeltaModel(IEdmModel source, IEdmEntityType entityType, IEnumerable<string> propertyNames) { _source = source; _entityType = new EdmEntityType(entityType.Namespace, entityType.Name); foreach (var property in entityType.StructuralProperties()) { if (propertyNames.Contains(property.Name)) _entityType.AddStructuralProperty(property.Name, property.Type, property.DefaultValueString, property.ConcurrencyMode); } foreach (var property in entityType.NavigationProperties()) { if (propertyNames.Contains(property.Name)) { var navInfo = new EdmNavigationPropertyInfo() { ContainsTarget = property.ContainsTarget, DependentProperties = property.DependentProperties(), PrincipalProperties = property.PrincipalProperties(), Name = property.Name, OnDelete = property.OnDelete, Target = property.Partner != null ? property.Partner.DeclaringEntityType() : property.Type.TypeKind() == EdmTypeKind.Collection ? (property.Type.Definition as IEdmCollectionType).ElementType.Definition as IEdmEntityType : property.Type.TypeKind() == EdmTypeKind.Entity ? property.Type.Definition as IEdmEntityType : null, TargetMultiplicity = property.TargetMultiplicity(), }; _entityType.AddUnidirectionalNavigation(navInfo); } } }
internal static string GetJsonPayload(IEdmEntityType entityType, object value) { Type valueType = value.GetType(); StringBuilder sb = new StringBuilder(); sb.Append("{"); sb.Append(Environment.NewLine); sb.Append("\t"); sb.Append("@odata.type: \"" + entityType.FullName() + "\","); var properties = entityType.StructuralProperties().ToList(); for (int i = 0; i < properties.Count; i++) { sb.Append("\t"); IEdmProperty property = properties[i]; // Type propertyType = ((PrimitiveType)property.TypeUsage.EdmType).ClrEquivalentType; PropertyInfo propertyInfo = valueType.GetProperty(property.Name); Type propertyType = propertyInfo.PropertyType; propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; object propertyValue = propertyInfo.GetValue(value, null); sb.Append(String.Format("{0}:{1}", properties[i].Name, PrimitiveToString(propertyValue, propertyType))); if (i != properties.Count - 1) { sb.Append(","); } sb.Append(Environment.NewLine); } sb.Append("}"); return(sb.ToString()); }
/// <summary> /// Create $orderby parameter for the <see cref="IEdmEntitySet"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="target">The Edm annotation target.</param> /// <returns>The created <see cref="OpenApiParameter"/> or null.</returns> public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(entityType, nameof(entityType)); SortRestrictions sort = context.Model.GetSortRestrictions(target); if (sort != null && !sort.IsSortable) { return(null); } IList <IOpenApiAny> orderByItems = new List <IOpenApiAny>(); foreach (var property in entityType.StructuralProperties()) { if (sort != null && sort.IsNonSortableProperty(property.Name)) { continue; } bool isAscOnly = sort != null?sort.IsAscendingOnlyProperty(property.Name) : false; bool isDescOnly = sort != null?sort.IsDescendingOnlyProperty(property.Name) : false; if (isAscOnly || isDescOnly) { if (isAscOnly) { orderByItems.Add(new OpenApiString(property.Name)); } else { orderByItems.Add(new OpenApiString(property.Name + " desc")); } } else { orderByItems.Add(new OpenApiString(property.Name)); orderByItems.Add(new OpenApiString(property.Name + " desc")); } } return(new OpenApiParameter { Name = "$orderby", In = ParameterLocation.Query, Description = "Order items by property values", Schema = new OpenApiSchema { // Remove array in favor of single instance for PowerApps Type = "string", Enum = orderByItems }, Style = ParameterStyle.Simple }); }
public static IList <string> CreateSelectItems(this IEdmEntityType entityType) { IList <string> selectItems = new List <string>(); foreach (var property in entityType.StructuralProperties()) { selectItems.Add(property.Name); } return(selectItems); }
/// <summary> /// Retrieves the paths for properties of type complex type from entities /// </summary> /// <param name="entityType">The entity type.</param> /// <param name="currentPath">The current path.</param> /// <param name="convertSettings">The settings for the current conversion.</param> private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath currentPath, OpenApiConvertSettings convertSettings) { Debug.Assert(entityType != null); Debug.Assert(currentPath != null); Debug.Assert(convertSettings != null); if (!convertSettings.EnableNavigationPropertyPath) { return; } foreach (IEdmStructuralProperty sp in entityType.StructuralProperties() .Where(x => x.Type.IsComplex() || x.Type.IsCollection() && x.Type.Definition.AsElementType() is IEdmComplexType)) { if (!ShouldCreateComplexPropertyPaths(sp, convertSettings)) { continue; } currentPath.Push(new ODataComplexPropertySegment(sp)); AppendPath(currentPath.Clone()); if (sp.Type.IsCollection()) { CreateTypeCastPaths(currentPath, convertSettings, sp.Type.Definition.AsElementType() as IEdmComplexType, sp, true); var count = _model.GetRecord <CountRestrictionsType>(sp, CapabilitiesConstants.CountRestrictions); if (count?.IsCountable ?? true) { CreateCountPath(currentPath, convertSettings); } } else { var complexTypeReference = sp.Type.AsComplex(); var definition = complexTypeReference.ComplexDefinition(); CreateTypeCastPaths(currentPath, convertSettings, definition, sp, false); foreach (IEdmNavigationProperty np in complexTypeReference .DeclaredNavigationProperties() .Union(definition .FindAllBaseTypes() .SelectMany(x => x.DeclaredNavigationProperties())) .Distinct() .Where(CanFilter)) { var count = _model.GetRecord <CountRestrictionsType>(np, CapabilitiesConstants.CountRestrictions); RetrieveNavigationPropertyPaths(np, count, currentPath, convertSettings); } } currentPath.Pop(); } }
internal EntityTypeInfo(IEdmModel edmModel, IEdmEntityType edmEntityType, ITypeResolver typeResolver) { Contract.Assert(edmModel != null); Contract.Assert(edmEntityType != null); Contract.Assert(typeResolver != null); _edmEntityType = edmEntityType; string edmTypeName = edmEntityType.FullName(); _type = typeResolver.ResolveTypeFromName(edmTypeName); // Initialize DontSerializeProperties _dontSerializeProperties = _type.GetProperties().Where(p => p.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), true).Length > 0).Select(p => p.Name).ToArray(); //edmEntityType.DeclaredKey; //edmEntityType.BaseEntityType(); var structuralProperties = new List<PropertyInfo>(); foreach (var edmStructuralProperty in edmEntityType.StructuralProperties()) { if (! _dontSerializeProperties.Contains(edmStructuralProperty.Name)) { structuralProperties.Add(_type.GetProperty(edmStructuralProperty.Name)); } } // EF can pick up private properties (eg: those marked as navigational). We omit them on spec. _structuralProperties = structuralProperties.Where(p => p != null).ToArray(); var navigationProperties = new List<PropertyInfo>(); var linkProperties = new List<PropertyInfo>(); foreach (var edmNavigationProperty in edmEntityType.NavigationProperties()) { if (! _dontSerializeProperties.Contains(edmNavigationProperty.Name)) { if (edmNavigationProperty.Type.IsCollection()) { linkProperties.Add(_type.GetProperty(edmNavigationProperty.Name)); } else { navigationProperties.Add(_type.GetProperty(edmNavigationProperty.Name)); } } } _navigationProperties = navigationProperties.Where(p => p != null).ToArray(); _collectionProperties = linkProperties.Where(p => p != null).ToArray(); // Reflect for ValidationAttributes on all properties var validationInfo = new List<PropertyValidationInfo>(); InitValidationInfo(validationInfo, _structuralProperties, PropertyCategory.Structural); InitValidationInfo(validationInfo, _navigationProperties, PropertyCategory.Navigation); InitValidationInfo(validationInfo, _collectionProperties, PropertyCategory.Collection); _propertyValidationInfo = validationInfo.ToArray(); }
// new CollectionWrapper<ElementType> { Instance = source.Select((ElementType element) => new Wrapper { }) } private Expression ProjectCollection(Expression source, Type elementType, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmEntitySet entitySet) { ParameterExpression element = Expression.Parameter(elementType); // expression // new Wrapper { } Expression projection = ProjectElement(element, selectExpandClause, entityType, entitySet); // expression // (ElementType element) => new Wrapper { } LambdaExpression selector = Expression.Lambda(projection, element); if (_settings.PageSize != null && _settings.PageSize.HasValue) { // nested paging. Need to apply order by first, and take one more than page size as we need to know // whether the collection was truncated or not while generating next page links. IEnumerable <IEdmStructuralProperty> properties = entityType.Key().Any() ? entityType.Key() : entityType .StructuralProperties() .Where(property => property.Type.IsPrimitive()).OrderBy(property => property.Name); bool alreadyOrdered = false; foreach (var prop in properties) { source = ExpressionHelpers.OrderByPropertyExpression(source, prop.Name, elementType, alreadyOrdered); if (!alreadyOrdered) { alreadyOrdered = true; } } source = ExpressionHelpers.Take(source, _settings.PageSize.Value + 1, elementType, _settings.EnableConstantParameterization); } // expression // source.Select((ElementType element) => new Wrapper { }) Expression selectedExpresion = Expression.Call(GetSelectMethod(elementType, projection.Type), source, selector); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : projectedCollection return(Expression.Condition( test: Expression.Equal(source, Expression.Constant(null)), ifTrue: Expression.Constant(null, selectedExpresion.Type), ifFalse: selectedExpresion)); } else { return(selectedExpresion); } }
public override IEnumerable <DynamicPropertyInfo> GetStructuralProperties(String tableName) { IEdmEntityType edmEntityType = OeEdmClrHelper.GetEntitySet(_edmModel, tableName).EntityType(); Type clrType = _edmModel.GetClrType(edmEntityType); foreach (IEdmStructuralProperty structuralProperty in edmEntityType.StructuralProperties()) { PropertyInfo property = clrType.GetProperty(structuralProperty.Name); DatabaseGeneratedAttribute attribute = property.GetCustomAttribute <DatabaseGeneratedAttribute>(); DatabaseGeneratedOption databaseGeneratedOption = attribute == null ? DatabaseGeneratedOption.None : databaseGeneratedOption = attribute.DatabaseGeneratedOption; yield return(new DynamicPropertyInfo(structuralProperty.Name, property.PropertyType, databaseGeneratedOption)); } }
public static IList <string> CreateOrderbyItems(this IEdmEntitySet entitySet) { IList <string> orderByItems = new List <string>(); IEdmEntityType entityType = entitySet.EntityType(); foreach (var property in entityType.StructuralProperties()) { orderByItems.Add(property.Name); orderByItems.Add(property.Name + " desc"); } return(orderByItems); }
// Returns a sorted list of all properties that may legally appear // in an OrderBy. If the entity type has keys, all are returned. // Otherwise, when no keys are present, all primitive properties are returned. private static IEnumerable <IEdmStructuralProperty> GetAvailableOrderByProperties(ODataQueryContext context) { Contract.Assert(context != null && context.EntitySet != null); IEdmEntityType entityType = context.EntitySet.ElementType; IEnumerable <IEdmStructuralProperty> properties = entityType.Key().Any() ? entityType.Key() : entityType .StructuralProperties() .Where(property => property.Type.IsPrimitive()); // Sort properties alphabetically for stable sort return(properties.OrderBy(property => property.Name)); }
private void CompareEntityType(IEdmEntityType expectedEntityType, IEdmEntityType actualEntityType) { this.SatisfiesEquals(expectedEntityType.FullName(), actualEntityType.FullName(), "EntityType name does not match."); this.SatisfiesEquals(expectedEntityType.IsAbstract, actualEntityType.IsAbstract, "IsAbstract does not match for EntityType '{0}'.", expectedEntityType.FullName()); string expectedBaseTypeName = expectedEntityType.BaseType != null ? ((IEdmSchemaElement)expectedEntityType.BaseType).FullName() : null; string actualBaseTypeName = actualEntityType.BaseType != null ? ((IEdmSchemaElement)actualEntityType.BaseType).FullName() : null; this.SatisfiesEquals(expectedBaseTypeName, actualBaseTypeName, "BaseType does not match for EntityType '{0}'.", expectedEntityType.FullName()); this.CompareProperties(expectedEntityType.StructuralProperties().Cast <IEdmProperty>(), actualEntityType.StructuralProperties().Cast <IEdmProperty>()); this.CompareProperties(expectedEntityType.Key().OfType <IEdmProperty>(), actualEntityType.Key().OfType <IEdmProperty>()); this.CompareNavigationProperty(expectedEntityType.Properties().OfType <IEdmNavigationProperty>(), actualEntityType.Properties().OfType <IEdmNavigationProperty>()); this.CompareTermAnnotations(expectedEntityType, actualEntityType); }
/// <summary> /// Create $select parameter for the <see cref="IEdmVocabularyAnnotatable"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="target">The Edm target.</param> /// <param name="entityType">The Edm entity type.</param> /// <returns>The created <see cref="OpenApiParameter"/> or null.</returns> public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(entityType, nameof(entityType)); NavigationRestrictionsType navigation = context.Model.GetRecord <NavigationRestrictionsType>(target, CapabilitiesConstants.NavigationRestrictions); if (navigation != null && !navigation.IsNavigable) { return(null); } IList <IOpenApiAny> selectItems = new List <IOpenApiAny>(); foreach (var property in entityType.StructuralProperties()) { selectItems.Add(new OpenApiString(property.Name)); } foreach (var property in entityType.NavigationProperties()) { if (navigation != null && navigation.IsRestrictedProperty(property.Name)) { continue; } selectItems.Add(new OpenApiString(property.Name)); } return(new OpenApiParameter { Name = "$select", In = ParameterLocation.Query, Description = "Select properties to be returned", Schema = new OpenApiSchema { Type = "array", UniqueItems = true, Items = new OpenApiSchema { Type = "string", Enum = selectItems } }, Style = ParameterStyle.Form }); }
/// <summary> /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties, /// navigation properties, and actions to select and expand for the given <paramref name="selectExpandClause"/>. /// </summary> /// <param name="selectExpandClause">The parsed $select and $expand query options.</param> /// <param name="entityType">The entity type of the entry that would be written.</param> /// <param name="model">The <see cref="IEdmModel"/> that contains the given entity type.</param> public SelectExpandNode(SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmModel model) : this() { if (entityType == null) { throw Error.ArgumentNull("entityType"); } if (model == null) { throw Error.ArgumentNull("model"); } HashSet<IEdmStructuralProperty> allStructuralProperties = new HashSet<IEdmStructuralProperty>(entityType.StructuralProperties()); HashSet<IEdmNavigationProperty> allNavigationProperties = new HashSet<IEdmNavigationProperty>(entityType.NavigationProperties()); HashSet<IEdmAction> allActions = new HashSet<IEdmAction>(model.GetAvailableActions(entityType)); HashSet<IEdmFunction> allFunctions = new HashSet<IEdmFunction>(model.GetAvailableFunctions(entityType)); if (selectExpandClause == null) { SelectedStructuralProperties = allStructuralProperties; SelectedNavigationProperties = allNavigationProperties; SelectedActions = allActions; SelectedFunctions = allFunctions; SelectAllDynamicProperties = true; } else { if (selectExpandClause.AllSelected) { SelectedStructuralProperties = allStructuralProperties; SelectedNavigationProperties = allNavigationProperties; SelectedActions = allActions; SelectedFunctions = allFunctions; SelectAllDynamicProperties = true; } else { BuildSelections(selectExpandClause, allStructuralProperties, allNavigationProperties, allActions, allFunctions); SelectAllDynamicProperties = false; } BuildExpansions(selectExpandClause, allNavigationProperties); // remove expanded navigation properties from the selected navigation properties. SelectedNavigationProperties.ExceptWith(ExpandedNavigationProperties.Keys); } }
// <summary> /// Create $select parameter for the <see cref="IEdmNavigationSource"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="navigationSource">The Edm navigation source.</param> /// <returns>The created <see cref="OpenApiParameter"/> or null.</returns> public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(entityType, nameof(entityType)); NavigationRestrictions navigation = context.Model.GetNavigationRestrictions(target); if (navigation != null && !navigation.IsNavigable) { return(null); } IList <IOpenApiAny> selectItems = new List <IOpenApiAny>(); foreach (var property in entityType.StructuralProperties()) { selectItems.Add(new OpenApiString(property.Name)); } foreach (var property in entityType.NavigationProperties()) { if (navigation != null && navigation.IsRestrictedProperty(property.Name)) { continue; } selectItems.Add(new OpenApiString(property.Name)); } return(new OpenApiParameter { Name = "$select", In = ParameterLocation.Query, Description = "Select properties to be returned", Schema = new OpenApiSchema { // Remove array in favor of single instance for PowerApps Type = "string", Enum = selectItems }, Style = ParameterStyle.Simple }); }
private static IEnumerable <string> PopuldateFieldList(IEdmEntityType entityType) { foreach (var property in entityType.StructuralProperties()) { yield return(property.Name); } foreach (var property in entityType.NavigationProperties()) { var typeKind = property.Type.TypeKind(); if (typeKind == EdmTypeKind.Entity) { var navigationPropertyType = property.Type.AsEntity(); foreach (var childProperty in navigationPropertyType.StructuralProperties()) { string propertyName = string.Format("{0}.{1}", property.Name, childProperty.Name); yield return(propertyName); } } } }
/// <summary> /// Gets the selected stream properties for the current node. /// </summary> /// <param name="entityType">The current entity type.</param> /// <returns>The selected stream properties.</returns> internal IDictionary <string, IEdmStructuralProperty> GetSelectedStreamProperties(IEdmEntityType entityType) { DebugUtils.CheckNoExternalCallers(); if (this.selectionType == SelectionType.Empty) { return(EmptyStreamProperties); } // We cannot determine the selected stream properties without the user model. This means we won't be computing the missing stream properties. // For reading we will report what's on the wire and for writing we just write what the user explicitely told us to write. if (entityType == null) { return(EmptyStreamProperties); } if (this.selectionType == SelectionType.EntireSubtree || this.hasWildcard) { return(entityType.StructuralProperties().Where(sp => sp.Type.IsStream()).ToDictionary(sp => sp.Name, StringComparer.Ordinal)); } Debug.Assert(this.selectedProperties != null, "selectedProperties != null"); IDictionary <string, IEdmStructuralProperty> selectedStreamProperties = this.selectedProperties .Select(entityType.FindProperty) .OfType <IEdmStructuralProperty>() .Where(p => p.Type.IsStream()) .ToDictionary(p => p.Name, StringComparer.Ordinal); // gather up the selected stream from any child nodes that have type segments matching the current type and add them to the dictionary. foreach (SelectedPropertiesNode typeSegmentChild in this.GetMatchingTypeSegments(entityType)) { var streamPropertiesForTypeSegment = typeSegmentChild.GetSelectedStreamProperties(entityType); foreach (var kvp in streamPropertiesForTypeSegment) { selectedStreamProperties[kvp.Key] = kvp.Value; } } return(selectedStreamProperties); }
private void CompareEntityWithPayload(XmlDocument document, object expectedInstance, IEdmEntityType entityType, string responseFormat) { foreach (var property in entityType.StructuralProperties()) { PropertyInfo propertyInfo = expectedInstance.GetType().GetProperty(property.Name); Type propertyType = propertyInfo.PropertyType; propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; object expectedValue = propertyInfo.GetValue(expectedInstance, null); ComparePropertyValue(document, propertyInfo, responseFormat, expectedValue); } }
private void PopulateResource(IEdmEntityType entityType, Dictionary<Type, TypeData> sampleValues, object instance, int index) { var properties = entityType.StructuralProperties().ToList(); for (int i = 0; i < properties.Count; i++) { IEdmProperty property = properties[i]; PropertyInfo propertyInfo = instance.GetType().GetProperty(property.Name); Type propertyType = propertyInfo.PropertyType; propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; TypeData sampleValueForType = sampleValues[propertyType]; object propertyValue; if (index < sampleValueForType.SampleValues.Length) { propertyValue = sampleValueForType.SampleValues[index]; } else { propertyValue = sampleValueForType.SampleValues[sampleValueForType.SampleValues.Length - 1]; } // set the property value propertyInfo.SetValue(instance, propertyValue, null); } }
private void CompareEntityType(IEdmEntityType expectedEntityType, IEdmEntityType actualEntityType) { this.SatisfiesEquals(expectedEntityType.FullName(), actualEntityType.FullName(), "EntityType name does not match."); this.SatisfiesEquals(expectedEntityType.IsAbstract, actualEntityType.IsAbstract, "IsAbstract does not match for EntityType '{0}'.", expectedEntityType.FullName()); string expectedBaseTypeName = expectedEntityType.BaseType != null ? ((IEdmSchemaElement)expectedEntityType.BaseType).FullName() : null; string actualBaseTypeName = actualEntityType.BaseType != null ? ((IEdmSchemaElement)actualEntityType.BaseType).FullName() : null; this.SatisfiesEquals(expectedBaseTypeName, actualBaseTypeName, "BaseType does not match for EntityType '{0}'.", expectedEntityType.FullName()); this.CompareProperties(expectedEntityType.StructuralProperties().Cast<IEdmProperty>(), actualEntityType.StructuralProperties().Cast<IEdmProperty>()); this.CompareProperties(expectedEntityType.Key().OfType<IEdmProperty>(), actualEntityType.Key().OfType<IEdmProperty>()); this.CompareNavigationProperty(expectedEntityType.Properties().OfType<IEdmNavigationProperty>(), actualEntityType.Properties().OfType<IEdmNavigationProperty>()); this.CompareTermAnnotations(expectedEntityType, actualEntityType); }
/// <summary> /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties, /// navigation properties, and actions to select and expand for the given <paramref name="selectExpandClause"/>. /// </summary> /// <param name="selectExpandClause">The parsed $select and $expand query options.</param> /// <param name="entityType">The entity type of the entry that would be written.</param> /// <param name="model">The <see cref="IEdmModel"/> that contains the given entity type.</param> public SelectExpandNode(SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmModel model) : this() { if (entityType == null) { throw Error.ArgumentNull("entityType"); } if (model == null) { throw Error.ArgumentNull("model"); } HashSet <IEdmStructuralProperty> allStructuralProperties = new HashSet <IEdmStructuralProperty>(entityType.StructuralProperties()); HashSet <IEdmNavigationProperty> allNavigationProperties = new HashSet <IEdmNavigationProperty>(entityType.NavigationProperties()); HashSet <IEdmAction> allActions = new HashSet <IEdmAction>(model.GetAvailableActions(entityType)); HashSet <IEdmFunction> allFunctions = new HashSet <IEdmFunction>(model.GetAvailableFunctions(entityType)); if (selectExpandClause == null) { SelectedStructuralProperties = allStructuralProperties; SelectedNavigationProperties = allNavigationProperties; SelectedActions = allActions; SelectedFunctions = allFunctions; SelectAllDynamicProperties = true; } else { if (selectExpandClause.AllSelected) { SelectedStructuralProperties = allStructuralProperties; SelectedNavigationProperties = allNavigationProperties; SelectedActions = allActions; SelectedFunctions = allFunctions; SelectAllDynamicProperties = true; } else { BuildSelections(selectExpandClause, allStructuralProperties, allNavigationProperties, allActions, allFunctions); SelectAllDynamicProperties = false; } BuildExpansions(selectExpandClause, allNavigationProperties); // remove expanded navigation properties from the selected navigation properties. SelectedNavigationProperties.ExceptWith(ExpandedNavigationProperties.Keys); } }
internal static string GetJsonPayload(IEdmEntityType entityType, object value) { Type valueType = value.GetType(); StringBuilder sb = new StringBuilder(); sb.Append("{"); sb.Append(Environment.NewLine); sb.Append("\t"); sb.Append("@odata.type: \"" + entityType.FullName() + "\","); var properties = entityType.StructuralProperties().ToList(); for (int i = 0; i < properties.Count; i++) { sb.Append("\t"); IEdmProperty property = properties[i]; // Type propertyType = ((PrimitiveType)property.TypeUsage.EdmType).ClrEquivalentType; PropertyInfo propertyInfo = valueType.GetProperty(property.Name); Type propertyType = propertyInfo.PropertyType; propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; object propertyValue = propertyInfo.GetValue(value, null); sb.Append(String.Format("{0}:{1}", properties[i].Name, PrimitiveToString(propertyValue, propertyType))); if (i != properties.Count - 1) { sb.Append(","); } sb.Append(Environment.NewLine); } sb.Append("}"); return sb.ToString(); }
internal AndConstraint <SelectedPropertiesNodeAssertions> IncludeEntireSubtree(IEdmEntityType entityType) { this.Subject.As <SelectedPropertiesNode>().GetSelectedStreamProperties(entityType).Values.Should().BeEquivalentTo(entityType.StructuralProperties().Where(p => p.Type.IsStream())); this.Subject.As <SelectedPropertiesNode>().GetSelectedNavigationProperties(entityType).Should().BeEquivalentTo(entityType.NavigationProperties()); foreach (var navigation in entityType.NavigationProperties()) { this.Subject.As <SelectedPropertiesNode>().GetSelectedPropertiesForNavigationProperty(entityType, navigation.Name).Should().HaveEntireSubtree(); } return(new AndConstraint <SelectedPropertiesNodeAssertions>(this)); }
// 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); } }
private IEdmStructuralProperty GetStructuralProperty(IEdmEntityType entityType, string identifier) { return(entityType.StructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier))); }
internal AndConstraint<SelectedPropertiesNodeAssertions> IncludeEntireSubtree(IEdmEntityType entityType) { this.Subject.As<SelectedPropertiesNode>().GetSelectedStreamProperties(entityType).Values.Should().BeEquivalentTo(entityType.StructuralProperties().Where(p => p.Type.IsStream())); this.Subject.As<SelectedPropertiesNode>().GetSelectedNavigationProperties(entityType).Should().BeEquivalentTo(entityType.NavigationProperties()); foreach (var navigation in entityType.NavigationProperties()) { this.Subject.As<SelectedPropertiesNode>().GetSelectedPropertiesForNavigationProperty(entityType, navigation.Name).Should().BeSameAsEntireSubtree(); } return new AndConstraint<SelectedPropertiesNodeAssertions>(this); }
/// <summary> /// Gets the selected stream properties for the current node. /// </summary> /// <param name="entityType">The current entity type.</param> /// <returns>The selected stream properties.</returns> internal IDictionary<string, IEdmStructuralProperty> GetSelectedStreamProperties(IEdmEntityType entityType) { if (this.selectionType == SelectionType.Empty) { return EmptyStreamProperties; } // We cannot determine the selected stream properties without the user model. This means we won't be computing the missing stream properties. // For reading we will report what's on the wire and for writing we just write what the user explicitely told us to write. if (entityType == null) { return EmptyStreamProperties; } if (this.selectionType == SelectionType.EntireSubtree || this.hasWildcard) { return entityType.StructuralProperties().Where(sp => sp.Type.IsStream()).ToDictionary(sp => sp.Name, StringComparer.Ordinal); } Debug.Assert(this.selectedProperties != null, "selectedProperties != null"); IDictionary<string, IEdmStructuralProperty> selectedStreamProperties = this.selectedProperties .Select(entityType.FindProperty) .OfType<IEdmStructuralProperty>() .Where(p => p.Type.IsStream()) .ToDictionary(p => p.Name, StringComparer.Ordinal); // gather up the selected stream from any child nodes that have type segments matching the current type and add them to the dictionary. foreach (SelectedPropertiesNode typeSegmentChild in this.GetMatchingTypeSegments(entityType)) { var streamPropertiesForTypeSegment = typeSegmentChild.GetSelectedStreamProperties(entityType); foreach (var kvp in streamPropertiesForTypeSegment) { selectedStreamProperties[kvp.Key] = kvp.Value; } } return selectedStreamProperties; }
public static IEnumerable <IEdmStructuralProperty> GetConcurrencyProperties(this IEdmEntityType type) { return(type.StructuralProperties() .Where(s => s.ConcurrencyMode == EdmConcurrencyMode.Fixed && s.Type.IsPrimitive())); }
private void VerifyMediaEntityGetOperation(string annotation, bool enableOperationId, bool useHTTPStatusCodeClass2XX) { // Arrange IEdmModel model = GetEdmModel(annotation); OpenApiConvertSettings settings = new OpenApiConvertSettings { EnableOperationId = enableOperationId, UseSuccessStatusCodeRange = useHTTPStatusCodeClass2XX }; ODataContext context = new ODataContext(model, settings); IEdmEntitySet todos = model.EntityContainer.FindEntitySet("Todos"); IEdmSingleton me = model.EntityContainer.FindSingleton("me"); Assert.NotNull(todos); Assert.NotNull(me); IEdmEntityType todo = model.SchemaElements.OfType <IEdmEntityType>().First(c => c.Name == "Todo"); IEdmStructuralProperty sp = todo.StructuralProperties().First(c => c.Name == "Logo"); ODataPath path = new ODataPath(new ODataNavigationSourceSegment(todos), new ODataKeySegment(todos.EntityType()), new ODataStreamPropertySegment(sp.Name)); IEdmEntityType user = model.SchemaElements.OfType <IEdmEntityType>().First(c => c.Name == "user"); IEdmNavigationProperty navProperty = user.NavigationProperties().First(c => c.Name == "photo"); ODataPath path2 = new ODataPath(new ODataNavigationSourceSegment(me), new ODataNavigationPropertySegment(navProperty), new ODataStreamContentSegment()); // Act var getOperation = _operationalHandler.CreateOperation(context, path); var getOperation2 = _operationalHandler.CreateOperation(context, path2); // Assert Assert.NotNull(getOperation); Assert.NotNull(getOperation2); Assert.Equal("Get Logo for Todo from Todos", getOperation.Summary); Assert.Equal("Get media content for the navigation property photo from me", getOperation2.Summary); Assert.NotNull(getOperation.Tags); Assert.NotNull(getOperation2.Tags); var tag = Assert.Single(getOperation.Tags); var tag2 = Assert.Single(getOperation2.Tags); Assert.Equal("Todos.Todo", tag.Name); Assert.Equal("me.profilePhoto", tag2.Name); Assert.NotNull(getOperation.Responses); Assert.NotNull(getOperation2.Responses); Assert.Equal(2, getOperation.Responses.Count); Assert.Equal(2, getOperation2.Responses.Count); var statusCode = useHTTPStatusCodeClass2XX ? Constants.StatusCodeClass2XX : Constants.StatusCode200; Assert.Equal(new[] { statusCode, "default" }, getOperation.Responses.Select(r => r.Key)); Assert.Equal(new[] { statusCode, "default" }, getOperation2.Responses.Select(r => r.Key)); if (!string.IsNullOrEmpty(annotation)) { Assert.Equal(2, getOperation.Responses[statusCode].Content.Keys.Count); Assert.True(getOperation.Responses[statusCode].Content.ContainsKey("image/png")); Assert.True(getOperation.Responses[statusCode].Content.ContainsKey("image/jpeg")); Assert.Equal("The logo image.", getOperation.Description); Assert.Equal(1, getOperation2.Responses[statusCode].Content.Keys.Count); Assert.True(getOperation2.Responses[statusCode].Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); } else { Assert.Equal(1, getOperation.Responses[statusCode].Content.Keys.Count); Assert.Equal(1, getOperation2.Responses[statusCode].Content.Keys.Count); Assert.True(getOperation.Responses[statusCode].Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); Assert.True(getOperation2.Responses[statusCode].Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); } if (enableOperationId) { Assert.Equal("Todos.Todo.GetLogo", getOperation.OperationId); Assert.Equal("me.GetPhotoContent", getOperation2.OperationId); } else { Assert.Null(getOperation.OperationId); Assert.Null(getOperation2.OperationId); } }