private void CreateNavigationMembers(QueryTypeLibrary library, QueryEntityType result, IEnumerable <NavigationProperty> navigationProperties, EntityContainer container) { foreach (var navprop in navigationProperties) { // handle MEST scenario where there are multiple association sets corresponding to a navigation property var asets = container.AssociationSets.Where(c => c.AssociationType == navprop.Association); var aset = asets.Single(set => set.Ends.Any(end => end.AssociationEnd == navprop.FromAssociationEnd && end.EntitySet == result.EntitySet)); var toSet = aset.Ends.Single(e => e.AssociationEnd == navprop.ToAssociationEnd).EntitySet; var targetEntityType = library.GetQueryEntityType(toSet, navprop.ToAssociationEnd.EntityType); QueryProperty property; if (navprop.ToAssociationEnd.Multiplicity == EndMultiplicity.Many) { // collection property property = QueryProperty.Create(navprop.Name, targetEntityType.CreateCollectionType()); } else { // reference property property = QueryProperty.Create(navprop.Name, targetEntityType); } result.Add(property); } }
/// <summary> /// Gets a queryExpression that represents a Query to an existing entity /// </summary> /// <param name="entityParameter">The LinqParameterExpression which represents the root parameter</param> /// <param name="existingEntity">The structural value representing an existing entity</param> /// <returns>A QueryExpression representing a query to an existing entity</returns> protected static QueryExpression GetExistingEntityKeyComparisonExpression(QueryExpression entityParameter, QueryStructuralValue existingEntity) { QueryExpression keyFilterExpression = null; QueryEntityType entityType = existingEntity.Type as QueryEntityType; foreach (var keyProperty in entityType.EntityType.AllKeyProperties) { var queryProperty = entityType.Properties.SingleOrDefault(p => p.Name == keyProperty.Name); ExceptionUtilities.CheckObjectNotNull(queryProperty, "Could not find property with name '{0}' on type '{1}'", keyProperty.Name, entityType); var value = existingEntity.GetScalarValue(keyProperty.Name); QueryExpression keyComparision = entityParameter.Property(keyProperty.Name).EqualTo(CommonQueryBuilder.Constant(value)); if (keyFilterExpression == null) { keyFilterExpression = keyComparision; } else { keyFilterExpression = CommonQueryBuilder.And(keyFilterExpression, keyComparision); } } return(keyFilterExpression); }
private void CreateStubEntityTypes(QueryTypeLibrary library, EntityContainer container) { foreach (var entitySet in container.EntitySets) { var rootType = entitySet.EntityType; var allDerivedTypes = container.Model.EntityTypes.Where(et => et.IsKindOf(rootType)); foreach (var entityType in allDerivedTypes) { QueryEntityType stub = this.CreateStubEntityType(entityType, entitySet); library.SetQueryEntityType(entitySet, entityType, stub); } // set up Parent for each type foreach (var childType in allDerivedTypes.Where(et => et != rootType)) { library.GetQueryEntityType(entitySet, childType).Parent = library.GetQueryEntityType(entitySet, childType.BaseType); } } // TODO: maybe this is wrong if >1 containers! Add unit test and fix. // construct DerivedTypes for each type foreach (var type in library.GetQueryEntityTypes()) { for (var parent = type.Parent; parent != null; parent = parent.Parent) { parent.DerivedTypes.Add(type); } } }
/// <summary> /// Builds an instance of QueryScalarValue from an primitiveValue instance. /// </summary> /// <param name="value">The primitiveValue instance</param> /// <param name="type">The QueryEntityType of the primitive</param> /// <returns>The converted scalar value.</returns> private QueryScalarValue BuildFromPrimitive(PrimitiveValue value, QueryEntityType type) { // Helpful for debugging purposes to understand when things fail, on which entity they fail on this.Logger.WriteLine(LogLevel.Trace, "Build From Primitive Instance with value: {0}", value.ClrValue); // convert to query value return (QueryScalarValue)this.PayloadElementToQueryValueConverter.Convert(value, type); }
private static void InitMemberStreamTypes(QueryEntityType type, QueryStructuralValue structural) { // initialize named streams foreach (var namedStream in type.Properties.Streams()) { AstoriaQueryStreamValue qsv = new AstoriaQueryStreamValue((AstoriaQueryStreamType)namedStream.PropertyType, (byte[])null, null, type.EvaluationStrategy); structural.SetStreamValue(namedStream.Name, qsv); } }
/// <summary> /// Initializes the given query type by creating a queryStreamValue to hold the expected values /// </summary> /// <param name="queryType">A QueryEntityType</param> /// <returns>a QueryStructurvalValue</returns> protected override QueryStructuralValue InitializeEntityValue(QueryEntityType queryType) { var entity = base.InitializeEntityValue(queryType); foreach (var namedStream in queryType.Properties.Streams()) { AstoriaQueryStreamValue qsv = new AstoriaQueryStreamValue((AstoriaQueryStreamType)namedStream.PropertyType, (byte[])null, null, queryType.EvaluationStrategy); entity.SetStreamValue(namedStream.Name, qsv); } return entity; }
/// <summary> /// Initializes the given query type by creating a queryStreamValue to hold the expected values /// </summary> /// <param name="queryType">A QueryEntityType</param> /// <returns>a QueryStructurvalValue</returns> protected override QueryStructuralValue InitializeEntityValue(QueryEntityType queryType) { var entity = base.InitializeEntityValue(queryType); foreach (var namedStream in queryType.Properties.Streams()) { AstoriaQueryStreamValue qsv = new AstoriaQueryStreamValue((AstoriaQueryStreamType)namedStream.PropertyType, (byte[])null, null, queryType.EvaluationStrategy); entity.SetStreamValue(namedStream.Name, qsv); } return(entity); }
/// <summary> /// Evaluates the specified expression. /// </summary> /// <param name="expression">The expression to evaluate.</param> /// <returns>Value of the expression.</returns> public QueryValue Visit(QueryOfTypeExpression expression) { QueryValue source = this.Evaluate(expression.Source); QueryEntityType resultType = expression.TypeToOperateAgainst as QueryEntityType; var argumentCollectionValue = source as QueryCollectionValue; ExceptionUtilities.Assert(argumentCollectionValue != null, "The argument to OfType has to be a collection of structural values"); ExceptionUtilities.Assert(argumentCollectionValue.Type.ElementType is QueryEntityType, "The argument to OfType has to be a collection of structural values"); return(argumentCollectionValue.OfType(resultType, false)); }
internal string CalculateExpectedETag(QueryValue expected) { if (!expected.IsNull) { QueryEntityType queryEntityType = expected.Type as QueryEntityType; if (queryEntityType != null) { return(this.LiteralConverter.ConstructWeakETag(expected as QueryStructuralValue)); } } return(null); }
private static ODataUri GetTopLevelUri(QueryStructuralValue entity) { ExceptionUtilities.CheckArgumentNotNull(entity, "entity"); QueryEntityType entityType = entity.Type as QueryEntityType; ExceptionUtilities.CheckObjectNotNull(entityType, "Given structural value was not an entity type"); var setSegment = ODataUriBuilder.EntitySet(entityType.EntitySet); var keyValues = entityType.EntityType.AllKeyProperties.Select(k => new NamedValue(k.Name, entity.GetScalarValue(k.Name).Value)); var keySegment = ODataUriBuilder.Key(entityType.EntityType, keyValues); return(new ODataUri(setSegment, keySegment)); }
private void FindEntitiesWithStreams(QueryRepository repository) { // Lambdas inside a Linq to objects query cannot refer to extension methods defined on types derived from non-system types. var streamRootQueries = repository.RootQueries.Collections <QueryStructuralType>(); foreach (var rootQuery in streamRootQueries) { QueryEntityType type = rootQuery.ExpressionType.ElementType as QueryEntityType; ExceptionUtilities.CheckObjectNotNull(type, "Type was not an entity type. Type was {0}", type.StringRepresentation); if (rootQuery.Expression.IsRootEntitySetQuery()) { if (!type.Properties.Streams().Any()) { continue; } var entitySetRightsAnnotation = type.EntitySet.Annotations.OfType <EntitySetRightsAnnotation>().SingleOrDefault(); // Skipping streams generation if EntitySetRights are not all if (entitySetRightsAnnotation != null && entitySetRightsAnnotation.Value != EntitySetRights.All) { continue; } var existing = this.QueryRepository.DataSet[type.EntitySet.Name]; ExceptionUtilities.Assert(existing != null, "Existing collection should not be null"); int i = 0; foreach (var qv in existing.Elements) { var qsv = qv as QueryStructuralValue; ExceptionUtilities.CheckObjectNotNull(qsv, "Should only be query structural value"); if (qsv.Type.Properties.Streams().Any()) { i++; this.queryStructuralValuesToAddStreamsTo.Add(qsv); this.queryStructuralValueToRootQueryLookup.Add(qsv, rootQuery.Expression); } } if (i > 0) { this.Logger.WriteLine(LogLevel.Verbose, "Adding streams to '{0}' entity Instances in Entity Set '{1}'", i, type.EntitySet.Name); } } } }
/// <summary> /// Initializes a new instance of the QueryKeyStructuralValue class. /// </summary> /// <param name="entityInstance">Entity Instance</param> internal QueryKeyStructuralValue(QueryEntityValue entityInstance) : base(entityInstance.Type, false, null, entityInstance.Type.EvaluationStrategy) { ExceptionUtilities.CheckArgumentNotNull(entityInstance, "entityInstance"); this.queryEntityType = entityInstance.Type as QueryEntityType; this.keyProperties = this.queryEntityType.Properties.Where(p => p.IsPrimaryKey).ToList(); ExceptionUtilities.CheckObjectNotNull(this.queryEntityType, "queryEntityType"); ExceptionUtilities.Assert(this.keyProperties.Count > 0, "There are no key properties on QueryEntityType '{0}'", this.queryEntityType); foreach (QueryProperty keyProperty in this.keyProperties) { this.SetValue(keyProperty.Name, entityInstance.GetScalarValue(keyProperty.Name)); } }
/// <summary> /// Finds the structural value for the given serializable entity and updates it, or create it if it does not exist /// </summary> /// <param name="baseType">The base type of the entity's set</param> /// <param name="entity">The entity to find and synchronize</param> /// <param name="existingEntityGraph">The existing entities in the set, mapped by key</param> /// <returns>The synchronized entity</returns> private QueryStructuralValue FindAndSynchronizeEntity(QueryEntityType baseType, SerializableEntity entity, IDictionary <EntityDataKey, QueryStructuralValue> existingEntityGraph) { QueryStructuralValue alreadySynchronized; if (this.synchronizationCache.TryGetValue(entity, out alreadySynchronized)) { return(alreadySynchronized); } // if the type does not match, it must be a derived type var type = baseType; if (type.EntityType.FullName != entity.EntityType) { type = type.DerivedTypes.Cast <QueryEntityType>().SingleOrDefault(t => t.EntityType.FullName == entity.EntityType); ExceptionUtilities.CheckObjectNotNull(type, "Could not find a type named '{0}'", entity.EntityType); } // compute the key for the entity var key = this.GetEntityKey(type, entity); QueryStructuralValue structural; bool isNewInstance = !existingEntityGraph.TryGetValue(key, out structural); // if we don't find it, create it if (isNewInstance) { structural = type.CreateNewInstance(); InitMemberStreamTypes(type, structural); } this.synchronizationCache[entity] = structural; this.SynchronizeProperties(baseType, entity, type, structural, existingEntityGraph); this.SynchronizeStreams(entity, structural); structural.MarkDynamicPropertyValues(); // if its a new instance, add it to the top-level collection if (isNewInstance) { this.QueryDataSet[type.EntitySet.Name].Elements.Add(structural); existingEntityGraph[this.GetEntityKey(structural)] = structural; } return(structural); }
/// <summary> /// Removes all references to the given entity /// </summary> /// <param name="type">The type of the entity</param> /// <param name="entity">The entity to remove</param> private void RemoveAllReferences(QueryEntityType type, QueryStructuralValue entity) { ExceptionUtilities.Assert(type == entity.Type, "QueryStructuralValue must have the same type as what is provided"); // get all association sets that touch the entity's set var associationSets = this.Model.EntityContainers .SelectMany(c => c.AssociationSets) .Where(a => a.Ends.Any(e => e.EntitySet == type.EntitySet && type.EntityType.IsKindOf(e.AssociationEnd.EntityType))) .ToList(); // get all the navigation properties for each set. Note that there will only be more than one in the case of a self-reference var navigationPropertiesBySet = associationSets .SelectMany(a => a.Ends) .ToLookup( e => e.EntitySet.Name, e => e.AssociationEnd.EntityType.AllNavigationProperties.SingleOrDefault(n => n.FromAssociationEnd == e.AssociationEnd)); // compute the key of this entity var key = this.GetEntityKey(entity); // go through each potentially-affected set and remove the entity from the navigations of each element foreach (var setNavigations in navigationPropertiesBySet) { var setName = setNavigations.Key; var setContents = this.QueryDataSet[setName].Elements.Cast <QueryStructuralValue>(); // go through each element in the set foreach (var related in setContents) { // and remove the entity from each navigation foreach (var navigation in setNavigations.Where(n => n != null)) { // We have associations between sub types in the hierarchy so some instances will not have particular associations so we should filter them out var relatedQueryEntityType = related.Type as QueryEntityType; if (relatedQueryEntityType.EntityType.IsKindOf(navigation.FromAssociationEnd.EntityType)) { this.RemoveFromNavigationProperty(key, related, navigation); } } } } }
/// <summary> /// Removes the given entity from the query data set /// Will remove all references to the entity if the provider is relational, and will delete any related objects that are marked as cascade-delete /// </summary> /// <param name="entity">The entity to remove</param> private void RemoveEntity(QueryStructuralValue entity) { ExceptionUtilities.CheckArgumentNotNull(entity, "entity"); QueryEntityType entityType = entity.Type as QueryEntityType; ExceptionUtilities.CheckObjectNotNull(entityType, "Value was not an entity"); // remove it from the top level set this.QueryDataSet[entityType.EntitySet.Name].Elements.Remove(entity); // remove all other references to this entity this.RemoveAllReferences(entityType, entity); // if any of this entity's relationships have cascading deletes, we need to emulate them foreach (var navigation in entityType.EntityType.AllNavigationProperties) { if (navigation.ToAssociationEnd.DeleteBehavior == OperationAction.Cascade) { if (navigation.ToAssociationEnd.Multiplicity == EndMultiplicity.Many) { var collection = entity.GetCollectionValue(navigation.Name); // recurse into the elements foreach (var related in collection.Elements.Cast <QueryStructuralValue>()) { this.RemoveEntity(related); } } else { // recurse into the reference var reference = entity.GetStructuralValue(navigation.Name); if (!reference.IsNull) { this.RemoveEntity(reference); } } } } }
/// <summary> /// Returns the expand string that represents the expression. /// </summary> /// <param name="lambdaExpression">The lambda expression to convert to an expand string.</param> /// <returns>String representation of the lambda expression.</returns> private static string ToExpandString(this QueryExpression lambdaExpression) { ExceptionUtilities.CheckArgumentNotNull(lambdaExpression, "lambdaExpression"); QueryPropertyExpression queryPropertyExpression = lambdaExpression as QueryPropertyExpression; ExceptionUtilities.CheckArgumentNotNull(queryPropertyExpression, "queryExpression as QueryPropertyExpression"); QueryAsExpression queryAsExpression = queryPropertyExpression.Instance as QueryAsExpression; if (queryAsExpression != null) { QueryEntityType queryEntityType = queryAsExpression.TypeToOperateAgainst as QueryEntityType; ExceptionUtilities.CheckObjectNotNull(queryEntityType, "The type to operate against for the query As expression is not a QueryEntityType"); return(queryEntityType.EntityType.FullName + "/" + queryPropertyExpression.Name); } else { return(queryPropertyExpression.Name); } }
private void SynchronizeProperties(QueryEntityType entitySetBaseType, SerializableEntity serializedEntity, QueryEntityType entityType, QueryStructuralValue entity, IDictionary <EntityDataKey, QueryStructuralValue> existingEntityGraph) { var originalPropertyNames = entity.MemberNames.ToList(); foreach (string streamName in entity.Type.Properties.Where(p => p.IsStream()).Select(p => p.Name)) { originalPropertyNames.Remove(streamName); } var nonNavigationValues = new List <NamedValue>(); // go throught the properties and recursively update any navigations, while saving the non-navigation properties for updating later foreach (var namedValue in serializedEntity.Properties) { NavigationProperty navProp = entityType.EntityType.AllNavigationProperties.Where(np => np.Name == namedValue.Name).SingleOrDefault(); if (navProp != null) { originalPropertyNames.Remove(namedValue.Name); this.SynchronizeNavigationProperty(entitySetBaseType, entity, namedValue, existingEntityGraph); } else { nonNavigationValues.Add(this.DataOracleConverter.Convert(namedValue)); } } // synchronize the non-navigation values this.StructuralUpdater.UpdateValues(entity, nonNavigationValues); // Remove all structural properties that have been s string[] structualMemberPropertiesUpdated = this.GetTopLevelPropertyNames(nonNavigationValues); foreach (string propertyName in originalPropertyNames) { if (!structualMemberPropertiesUpdated.Contains(propertyName)) { entity.RemoveMember(propertyName); } } }
/// <summary> /// Build Library Without Clr Type Mappings based on the EntityModelSchema given /// </summary> /// <param name="model">Entity Model Schema to create Query Model of</param> /// <returns>Query Type Library of Entity Model Schema</returns> public override QueryTypeLibrary BuildLibraryWithoutClrTypeMapping(EntityModelSchema model) { QueryTypeLibrary queryTypeLibrary = base.BuildLibraryWithoutClrTypeMapping(model); // add new properties for each of the named streams annotations to the query entity type to be used for verification foreach (var container in model.EntityContainers) { foreach (var entitySet in container.EntitySets) { foreach (EntityType entityType in model.EntityTypes.Where(t => t.IsKindOf(entitySet.EntityType))) { QueryEntityType queryEntityType = queryTypeLibrary.GetQueryEntityType(entitySet, entityType); // add the named streams properties foreach (var streamProperty in queryEntityType.EntityType.Properties.Where(p => p.IsStream())) { queryEntityType.Add(new QueryProperty <AstoriaQueryStreamType>(streamProperty.Name, new AstoriaQueryStreamType(this.strategy))); foreach (QueryEntityType qet in queryEntityType.DerivedTypes) { qet.Add(new QueryProperty <AstoriaQueryStreamType>(streamProperty.Name, new AstoriaQueryStreamType(this.strategy))); } } // add the default stream property if (entityType.HasStream()) { var queryStreamType = new AstoriaQueryStreamType(this.strategy); queryEntityType.Add(new QueryProperty <AstoriaQueryStreamType>(AstoriaQueryStreamType.DefaultStreamPropertyName, queryStreamType)); foreach (QueryEntityType qet in queryEntityType.DerivedTypes) { qet.Add(new QueryProperty <AstoriaQueryStreamType>(AstoriaQueryStreamType.DefaultStreamPropertyName, new AstoriaQueryStreamType(this.strategy))); } } } } } return(queryTypeLibrary); }
public override string ToString() { RequestSortField = SortField; RequestSortDirection = SortDirection; if (QueryEntityType != null) { Dictionary <string, string> map; if (!_sortTypes.TryGetValue(QueryEntityType, out map)) { map = new Dictionary <string, string>(); PropertyInfo[] infos = QueryEntityType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo info in infos) { object[] attributes = info.GetCustomAttributes(typeof(SortAttribute), true); if (attributes != null && attributes.Length > 0) { foreach (object attribute in attributes) { if (attribute is SortAttribute) { map.Add(info.Name, (attribute as SortAttribute).Name); break; } } } } _sortTypes.TryAdd(QueryEntityType, map); } string name; if (!string.IsNullOrEmpty(SortField) && map.TryGetValue(SortField, out name)) { RequestSortField = name; RequestSortDirection = SortDirection; } } return(base.ToString()); }
/// <summary> /// Gets EDM type for primtive, entity and complex types /// </summary> /// <param name="type">The Query Type.</param> /// <returns>The EDM Type in string format.</returns> protected string GetEdmTypeName(QueryType type) { QueryComplexType complexType = type as QueryComplexType; QueryEntityType entityType = type as QueryEntityType; IQueryClrType clrBackedType = type as IQueryClrType; if (complexType != null) { return(complexType.ComplexType.FullName); } else if (entityType != null) { return(entityType.EntityType.FullName); } else if (clrBackedType != null) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveDataTypeConverter, "Cannot get edm type name for primitive clr type without converter"); return(this.PrimitiveDataTypeConverter.ToDataType(clrBackedType.ClrType).GetEdmTypeName()); } else { throw new TaupoNotSupportedException("Unable to find EDM type name for type which is not an entity type or a primitive type"); } }
/// <summary> /// Creates a QueryValue of a given type. /// </summary> /// <param name="type">Type of the QueryValue that will be generated.</param> /// <returns>QueryValue representing the provided object.</returns> public QueryValue Visit(QueryEntityType type) { var resultFragment = this.ResultFragmentStack.Pop(); QueryStructuralValue visitedEntity; if (this.visitedStructurals.TryGetValue(resultFragment, out visitedEntity)) { return(visitedEntity); } // taking inheritance into account - while 'expected' query entity type is Product, the actual materialized object can be DiscontinuedProduct var entityTypeHierarchy = new[] { type }.Concat(type.DerivedTypes).Cast <QueryEntityType>(); var matchingEntityType = entityTypeHierarchy.Where(et => et.EntityType.Name == resultFragment.GetType().Name).SingleOrDefault(); ExceptionUtilities.CheckObjectNotNull(matchingEntityType, "Could not find " + typeof(QueryEntityType).Name + " that would match the given type: " + resultFragment.GetType().Name); var resultEntity = matchingEntityType.CreateNewInstance(); this.visitedStructurals[resultFragment] = resultEntity; resultEntity = this.PopulateProperties(resultEntity, resultFragment); return(resultEntity); }
/// <summary> /// Compares Collections, optimizes entity collection comparisons for better error messages or defers to the base /// </summary> /// <param name="expected">Expected Value</param> /// <param name="actualElements">Actual Elements to compare against</param> /// <param name="path">Path of the elements</param> /// <param name="shouldThrow">Should throw on error or not</param> /// <param name="comparisonSkippedForAnyElement">Skip for particular comparisons</param> /// <returns>A Comparison result</returns> protected override ComparisonResult CompareCollections(QueryCollectionValue expected, IEnumerable <object> actualElements, string path, bool shouldThrow, out bool comparisonSkippedForAnyElement) { comparisonSkippedForAnyElement = false; QueryEntityType queryEntityType = expected.Type.ElementType as QueryEntityType; if (queryEntityType != null) { List <QueryProperty> keyProperties = queryEntityType.Properties.Where(p => p.IsPrimaryKey).ToList(); ExceptionUtilities.Assert(queryEntityType.Properties.Where(p => p.IsPrimaryKey).Count() > 0, "QueryEntityType '{0}' must have a Primary key defined in order to compare using primary keys", queryEntityType.EntityType.FullName); List <object> unprocessableElements = actualElements.Where(e => !queryEntityType.ClrType.IsAssignableFrom(e.GetType())).ToList(); if (unprocessableElements.Count > 0) { string errorDetails = string.Join(", ", unprocessableElements.Select(o => string.Format(CultureInfo.InvariantCulture, "Expected object '{0}' to be assignable to '{1}'", o.GetType().FullName, queryEntityType.ClrType.FullName)).ToArray()); this.ThrowOrLogError(shouldThrow, "There are '{0}' elements that are unprocessable, Details '{1}'", unprocessableElements.Count, errorDetails); return(ComparisonResult.Failure); } List <object> unprocessedElements = actualElements.Where(e => queryEntityType.ClrType.IsAssignableFrom(e.GetType())).ToList(); foreach (QueryStructuralValue queryStructuralValue in expected.Elements) { var queryEntityValue = queryStructuralValue as QueryEntityValue; ExceptionUtilities.CheckObjectNotNull(queryEntityValue, "Expected Collection element to be a 'QueryEntityValue', got a '{0}' instead", queryStructuralValue); ExceptionUtilities.CheckObjectNotNull(queryEntityValue.IsNull, "Expected Collection of QueryEntityValues to not contain a QueryEntityValue that is null '{0}'", queryEntityValue.ToString()); // Note: We could fix this limitation by simply using the normal unsorted code path instead in these cases but no point implementing this unless its needed. ExceptionUtilities.CheckObjectNotNull(keyProperties.Select(kp => queryEntityValue.GetScalarValue(kp.Name).IsNull).Any(), "Error: QueryEntityValue must have key values defined"); QueryKeyStructuralValue key = queryEntityValue.Key(); object entityInstance = unprocessedElements.Where(upe => queryEntityType.GetEntityInstanceKey(upe).Equals(key)).SingleOrDefault(); if (entityInstance == null) { this.ThrowOrLogError(shouldThrow, "Cannot find actual EntityInstance that is assignable to type '{0}' with key '{1}' in expected collection '{2}'", queryEntityType.EntityType.FullName, key.GetDebugKeyString(), expected); return(ComparisonResult.Failure); } else { unprocessedElements.Remove(entityInstance); string childPath = string.Format(CultureInfo.InvariantCulture, "{0}.CollectionItem(ElementType='{1}',Key='{2}')", path, queryEntityType.EntityType.FullName, key.GetDebugKeyString()); ComparisonResult innerResult = this.Compare(queryEntityValue, entityInstance, childPath, false); if (innerResult == ComparisonResult.Failure) { this.DisplayLog(); this.ThrowOrLogError(shouldThrow, "Comparision of EntityInstance in path '{0}' failed, see log for details", childPath, key.GetDebugKeyString(), expected); return(ComparisonResult.Failure); } } } if (unprocessedElements.Count > 0) { string errorDetails = string.Join(", ", unprocessedElements.Select(o => string.Format(CultureInfo.InvariantCulture, "Actual EntityInstance of type '{0}' with key '{1}' is not contained in expected collection '{2}'", o.GetType().FullName, queryEntityType.GetEntityInstanceKey(o).GetDebugKeyString(), expected)).ToArray()); this.ThrowOrLogError(shouldThrow, "There are '{0}' elements that are unprocessable, Details '{1}'", unprocessedElements.Count, errorDetails); return(ComparisonResult.Failure); } return(ComparisonResult.Success); } else { return(base.CompareCollections(expected, actualElements, path, shouldThrow, out comparisonSkippedForAnyElement)); } }
private void CreateNavigationMembers(QueryTypeLibrary library, QueryEntityType result, IEnumerable<NavigationProperty> navigationProperties, EntityContainer container) { foreach (var navprop in navigationProperties) { // handle MEST scenario where there are multiple association sets corresponding to a navigation property var asets = container.AssociationSets.Where(c => c.AssociationType == navprop.Association); var aset = asets.Single(set => set.Ends.Any(end => end.AssociationEnd == navprop.FromAssociationEnd && end.EntitySet == result.EntitySet)); var toSet = aset.Ends.Single(e => e.AssociationEnd == navprop.ToAssociationEnd).EntitySet; var targetEntityType = library.GetQueryEntityType(toSet, navprop.ToAssociationEnd.EntityType); QueryProperty property; if (navprop.ToAssociationEnd.Multiplicity == EndMultiplicity.Many) { // collection property property = QueryProperty.Create(navprop.Name, targetEntityType.CreateCollectionType()); } else { // reference property property = QueryProperty.Create(navprop.Name, targetEntityType); } result.Add(property); } }
private void CompareValues(QueryStructuralValue instance, IEnumerable <NamedValue> namedValues, string propertyPath) { foreach (QueryProperty property in instance.Type.Properties) { string childPropertyPath = property.Name; if (propertyPath != null) { childPropertyPath = propertyPath + "." + property.Name; } // Skip if its an EntityType, this only handles structural types var queryEntityType = property.PropertyType as QueryEntityType; if (queryEntityType != null) { continue; } var collectionType = property.PropertyType as QueryCollectionType; var scalarType = property.PropertyType as QueryScalarType; var complexDataType = property.PropertyType as QueryComplexType; QueryEntityType collectionQueryElementType = null; if (collectionType != null) { collectionQueryElementType = collectionType.ElementType as QueryEntityType; } // Skip if its a collection of QueryEntityType if (collectionQueryElementType != null) { continue; } if (scalarType != null) { // The following code block handles the case where the value is server generated. // For instance, server generated Keys would fail so if a property is marked as being server generated // we make sure to remove that property from the list of properties to verify MemberProperty memberProperty; var instanceEntityType = instance.Type as QueryEntityType; if (instanceEntityType != null) { memberProperty = instanceEntityType.EntityType.AllProperties.SingleOrDefault(p => p.Name == property.Name); } else { memberProperty = ((QueryComplexType)instance.Type).ComplexType.Properties.SingleOrDefault(p => p.Name == property.Name); } if (memberProperty != null && memberProperty.Annotations.OfType <StoreGeneratedPatternAnnotation>().Any()) { // TODO: be more fine-grained about whether this is an update or insert (ie, look at the annotation's property values) this.unusedNamedValuePaths.Remove(childPropertyPath); continue; } NamedValue primitivePropertyNamedValue = namedValues.SingleOrDefault(nv => nv.Name == childPropertyPath); if (primitivePropertyNamedValue != null) { var queryValue = instance.GetScalarValue(property.Name); this.WriteErrorIfNotEqual(childPropertyPath, primitivePropertyNamedValue.Value, queryValue); this.unusedNamedValuePaths.Remove(childPropertyPath); } } else if (collectionType != null) { List <NamedValue> bagNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList(); if (bagNamedValues.Any()) { this.CompareBagProperty(instance, property, collectionType.ElementType, childPropertyPath, bagNamedValues); } else { this.CompareBagPropertyWithNullOrEmpty(instance, property, childPropertyPath, namedValues); } } else if (complexDataType != null) { // NOTE: we cannot assert that it is complex/primitive/bag, because there may be new query types added in other assemblies that we know nothing about here QueryStructuralValue complexTypeValue = instance.GetStructuralValue(property.Name); List <NamedValue> complexInstanceNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList(); if (complexInstanceNamedValues.Any()) { if (!this.WriteErrorIfNull(childPropertyPath, complexTypeValue)) { this.CompareValues(complexTypeValue, complexInstanceNamedValues, childPropertyPath); } } else { // Check for null case List <NamedValue> exactMatches = namedValues.Where(nv => nv.Name == childPropertyPath).ToList(); ExceptionUtilities.Assert(exactMatches.Count < 2, "Should only find at most one property path {0} when looking for null value", childPropertyPath); if (exactMatches.Count == 1) { ExceptionUtilities.Assert( exactMatches[0].Value == null, "Named value at path '{0}' was unexpectedly non-null. Value was '{1}'", childPropertyPath, exactMatches[0].Value); QueryValue queryValue = instance.GetValue(property.Name); this.WriteErrorIfNotNull(childPropertyPath, queryValue); this.unusedNamedValuePaths.Remove(childPropertyPath); } } } } }
/// <summary> /// Generates new property values for the given type using this test's structural data services /// </summary> /// <param name="type">The type to generate properties for</param> /// <returns>A set of new property values for the given type</returns> protected internal IEnumerable <NamedValue> GeneratePropertyValues(QueryEntityType type) { ExceptionUtilities.CheckArgumentNotNull(type, "type"); return(this.GeneratePropertyValues(type.EntitySet, type.EntityType)); }
/// <summary> /// Generates a set of values for an entity type's key properties. Will throw if any key property is a dependent/foreign-key. For composite keys, only one of the values is guaranteed to be unique. /// </summary> /// <param name="type">The entity type to generate a key for</param> /// <returns>The key property values in metadata order</returns> protected internal IEnumerable <NamedValue> GeneratePropertyValuesWithUniqueKey(QueryEntityType type) { return(this.GeneratePropertyValuesWithUniqueKey(type.EntitySet, type.EntityType)); }
internal void UpdateValues(QueryStructuralValue instance, IEnumerable <NamedValue> namedValues, string propertyPath) { foreach (QueryProperty property in instance.Type.Properties) { string childPropertyPath = property.Name; if (propertyPath != null) { childPropertyPath = propertyPath + "." + property.Name; } // Skip if its an EntityType, this only handles structural types var queryEntityType = property.PropertyType as QueryEntityType; if (queryEntityType != null) { continue; } var collectionType = property.PropertyType as QueryCollectionType; var scalarType = property.PropertyType as QueryScalarType; var complexDataType = property.PropertyType as QueryComplexType; QueryEntityType collectionQueryElementType = null; if (collectionType != null) { collectionQueryElementType = collectionType.ElementType as QueryEntityType; } // Skip if its a collection of QueryEntityType if (collectionQueryElementType != null) { continue; } if (scalarType != null) { NamedValue primitivePropertyNamedValue = namedValues.SingleOrDefault(nv => nv.Name == childPropertyPath); if (primitivePropertyNamedValue != null) { instance.SetPrimitiveValue(property.Name, primitivePropertyNamedValue.Value); this.unusedNamedValuePaths.Remove(childPropertyPath); } } else if (collectionType != null) { List <NamedValue> bagNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList(); if (bagNamedValues.Any()) { this.UpdateBagProperty(instance, property, collectionType.ElementType, childPropertyPath, bagNamedValues); } else { this.UpdateBagPropertyWithNullOrEmpty(instance, property, childPropertyPath, namedValues); } } else if (complexDataType != null) { // NOTE: we cannot assert that it is complex/primitive/bag, because there may be new query types added in other assemblies that we know nothing about here QueryStructuralValue complexTypeValue = instance.GetStructuralValue(property.Name); List <NamedValue> complexInstanceNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList(); if (complexInstanceNamedValues.Any()) { if (complexTypeValue.IsNull) { complexTypeValue = complexDataType.CreateNewInstance(); } this.UpdateValues(complexTypeValue, complexInstanceNamedValues, childPropertyPath); instance.SetValue(property.Name, complexTypeValue); } else { // Check for null case List <NamedValue> exactMatches = namedValues.Where(nv => nv.Name == childPropertyPath).ToList(); ExceptionUtilities.Assert(exactMatches.Count < 2, "Should only find at most one property path {0} when looking for null value", childPropertyPath); if (exactMatches.Count == 1) { ExceptionUtilities.Assert( exactMatches[0].Value == null, "Named value at path '{0}' was unexpectedly non-null. Value was '{1}'", childPropertyPath, exactMatches[0].Value); instance.SetValue(property.Name, complexDataType.NullValue); this.unusedNamedValuePaths.Remove(childPropertyPath); } } } } }
/// <summary> /// Verify ETag and Id values of given payload element. /// </summary> /// <param name="entityType">type of the element</param> /// <param name="payloadElement">payload element to verify</param> /// <param name="value">expected values</param> private void VerifyEntityMetadata(QueryEntityType entityType, EntityInstance payloadElement, QueryStructuralValue value) { if (this.parent.ExpectedPayloadOptions.HasFlag(ODataPayloadOptions.IncludeETags)) { if (entityType.EntityType.HasETag()) { // TODO: are ETags always based on property values? var expectedETag = this.parent.LiteralConverter.ConstructWeakETag(value); this.parent.Assert.AreEqual(expectedETag, payloadElement.ETag, "Entity's ETag did not match"); } else { this.parent.Assert.IsNull(payloadElement.ETag, "Entity should not have had an ETag"); } } if (this.parent.ExpectedPayloadOptions.HasFlag(ODataPayloadOptions.IncludeEntityIdentifier)) { this.parent.Assert.IsNotNull(payloadElement.Id, "Entity's ID unexpectedly null"); if (this.parent.ExpectedPayloadOptions.HasFlag(ODataPayloadOptions.UseConventionBasedIdentifiers)) { var expectedId = this.parent.LinkGenerator.GenerateEntityId(value); this.parent.Assert.AreEqual(expectedId, payloadElement.Id, "Entity's ID did not match"); } } else { this.parent.Assert.IsNull(payloadElement.Id, "Entity's ID unexpectedly non-null"); } if (this.parent.ExpectedPayloadOptions.HasFlag(ODataPayloadOptions.UseConventionBasedLinks)) { var expectedEditLink = this.parent.LinkGenerator.GenerateEntityEditLink(value); this.CompareUri(expectedEditLink, payloadElement.EditLink, "Entity's edit-link did not match"); } if (entityType.EntityType.GetBaseTypesAndSelf().Any(t => t.HasStream())) { using (this.parent.Assert.WithMessage("Entity's stream metadata did not match")) { var defaultStreamValue = value.GetDefaultStreamValue(); this.parent.Assert.AreEqual(defaultStreamValue.ContentType, payloadElement.StreamContentType, "Content type did not match"); this.CompareStreamETag(defaultStreamValue, payloadElement.StreamETag); if (this.parent.ExpectedPayloadOptions.HasFlag(ODataPayloadOptions.IncludeMediaResourceEditLinks)) { this.CompareUri(defaultStreamValue.EditLink, payloadElement.StreamEditLink, "Edit link did not match"); } else { this.parent.Assert.IsNull(payloadElement.StreamEditLink, "Edit link unexpectedly non-null"); } if (this.parent.ExpectedPayloadOptions.HasFlag(ODataPayloadOptions.IncludeMediaResourceSourceLinks)) { this.CompareUri(defaultStreamValue.SelfLink, payloadElement.StreamSourceLink, "Source link did not match"); } else { this.parent.Assert.IsNull(payloadElement.StreamSourceLink, "Source link unexpectedly non-null"); } } } }
/// <summary> /// Initializes a new instance of the QueryEntityValue class. /// </summary> /// <param name="type">The type of the value.</param> /// <param name="isNull">If set to <c>true</c> the structural value is null.</param> /// <param name="evaluationError">The evaluation error.</param> /// <param name="evaluationStrategy">The evaluation strategy.</param> internal QueryEntityValue(QueryEntityType type, bool isNull, QueryError evaluationError, IQueryEvaluationStrategy evaluationStrategy) : base(type, isNull, evaluationError, evaluationStrategy) { this.navigateResultLookup = new Dictionary<AssociationType, Dictionary<AssociationEnd, QueryValue>>(); }
/// <summary> /// Initializes the given queryType /// </summary> /// <param name="queryType">the query type to initialize</param> /// <returns>the query structurval value</returns> protected virtual QueryStructuralValue InitializeEntityValue(QueryEntityType queryType) { return(queryType.CreateNewInstance()); }
/// <summary> /// Builds an instance of QueryCollectionValue from an entity set instance. /// </summary> /// <param name="entitySetInstance">The entity set instance.</param> /// <param name="elementType">The QueryEntityType of its element.</param> /// <param name="xmlBaseAnnotations">The xml base annotations from parent elements, if any</param> /// <returns>The converted QueryCollectionValue of entity set instance.</returns> private QueryCollectionValue BuildFromEntitySetInstance(EntitySetInstance entitySetInstance, QueryEntityType elementType, IEnumerable<XmlBaseAnnotation> xmlBaseAnnotations) { ExceptionUtilities.CheckArgumentNotNull(elementType, "elementType"); var entities = new List<QueryValue>(); QueryValue value; foreach (var instance in entitySetInstance) { EntityInstance entity = instance as EntityInstance; if (entity != null) { value = this.BuildFromEntityInstance(entity, elementType, xmlBaseAnnotations.Concat(entity.Annotations.OfType<XmlBaseAnnotation>())); } else { value = this.BuildFromPrimitive((PrimitiveValue)instance, elementType); } entities.Add(value); } return QueryCollectionValue.Create(elementType, entities.ToArray()); }
/// <summary> /// Generates new property values for the given type using this test's structural data services /// </summary> /// <param name="type">The type to generate properties for</param> /// <returns>A set of new property values for the given type</returns> protected internal IEnumerable<NamedValue> GeneratePropertyValues(QueryEntityType type) { ExceptionUtilities.CheckArgumentNotNull(type, "type"); return this.GeneratePropertyValues(type.EntitySet, type.EntityType); }
/// <summary> /// Builds an instance of QueryCollectionValue from an entity set instance. /// </summary> /// <param name="entitySetInstance">The entity set instance.</param> /// <param name="elementType">The QueryEntityType of its element.</param> /// <param name="xmlBaseAnnotations">The xml base annotations from parent elements, if any</param> /// <returns>The converted QueryCollectionValue of entity set instance.</returns> private QueryCollectionValue BuildFromEntitySetInstance(EntitySetInstance entitySetInstance, QueryEntityType elementType, IEnumerable <XmlBaseAnnotation> xmlBaseAnnotations) { ExceptionUtilities.CheckArgumentNotNull(elementType, "elementType"); var entities = new List <QueryStructuralValue>(); foreach (var entityInstance in entitySetInstance) { var value = this.BuildFromEntityInstance(entityInstance, elementType, xmlBaseAnnotations.Concat(entityInstance.Annotations.OfType <XmlBaseAnnotation>())); entities.Add(value); } return(QueryCollectionValue.Create(elementType, entities.ToArray())); }
/// <summary> /// Builds an instance of QueryStructureValue from an entity instance. /// </summary> /// <param name="instance">The entity instance</param> /// <param name="type">The QueryEntityType of the entity</param> /// <param name="xmlBaseAnnotations">The xml base annotations from parent elements, if any</param> /// <returns>The converted structural value of entity instance.</returns> private QueryStructuralValue BuildFromEntityInstance(EntityInstance instance, QueryEntityType type, IEnumerable <XmlBaseAnnotation> xmlBaseAnnotations) { QueryStructuralValue entity; // Helpful for debugging purposes to understand when things fail, on which entity they fail on this.Logger.WriteLine(LogLevel.Trace, "Build From Entity Instance with Id: {0}", instance.Id); // handle MEST. var queryEntityType = type; if (type.EntityType.FullName != instance.FullTypeName) { queryEntityType = type.DerivedTypes.Cast <QueryEntityType>().SingleOrDefault(t => t.EntityType.FullName == instance.FullTypeName); ExceptionUtilities.CheckObjectNotNull(queryEntityType, "Cannot find query entity type for entity type {0}.", instance.FullTypeName); } if (!instance.Annotations.OfType <DataTypeAnnotation>().Any()) { instance.Annotations.Add(new DataTypeAnnotation() { DataType = DataTypes.EntityType.WithDefinition(queryEntityType.EntityType) }); } // remove navigation properties so that they can be added after var navigationProperties = instance.Properties.OfType <NavigationPropertyInstance>().ToList(); navigationProperties.ForEach(n => instance.Remove(n)); // convert to query value entity = (QueryStructuralValue)this.PayloadElementToQueryValueConverter.Convert(instance, queryEntityType); // add expanded navigation properties. this.AddNavigationProperties(entity, navigationProperties.Where(p => p.IsExpanded), xmlBaseAnnotations); // add stream properties this.AddStreamProperties(entity, instance, xmlBaseAnnotations); return(entity); }
private void SynchronizeNavigationProperty(QueryEntityType entitySetBaseType, QueryStructuralValue entity, SerializableNamedValue namedValue, IDictionary <EntityDataKey, QueryStructuralValue> existingEntityGraph) { var reference = namedValue.Value as SerializableEntity; if (reference != null) { QueryStructuralValue synchronized; if (reference.EntitySetName == entitySetBaseType.EntitySet.Name) { // for self references, we don't need to rebuild the set of existing entities synchronized = this.FindAndSynchronizeEntity(entitySetBaseType, reference, existingEntityGraph); } else { synchronized = this.FindAndSynchronizeEntity(reference); } entity.SetValue(namedValue.Name, synchronized); return; } var collection = namedValue.Value as IEnumerable <SerializableEntity>; if (collection != null) { var oldCollection = entity.GetCollectionValue(namedValue.Name); // clear out the old collection, if it exists if (entity.MemberNames.Contains(namedValue.Name)) { oldCollection.Elements.Clear(); } else { // by default we set IsSorted to true, enabling ordering verification. oldCollection = QueryCollectionValue.Create(oldCollection.Type.ElementType, new QueryValue[0], true); } entity.SetValue(namedValue.Name, oldCollection); // go through the new elements, synchronize them, and add them foreach (var related in collection) { QueryStructuralValue synchronized; if (related.EntitySetName == entitySetBaseType.EntitySet.Name) { // for self references, we don't need to rebuild the set of existing entities synchronized = this.FindAndSynchronizeEntity(entitySetBaseType, related, existingEntityGraph); } else { synchronized = this.FindAndSynchronizeEntity(related); } oldCollection.Elements.Add(synchronized); } return; } ExceptionUtilities.Assert(namedValue.Value == null, "Value of navigation property '{0}' was not a reference, a collection of references, or null. Value was '{1}'", namedValue.Name, namedValue.Value); entity.SetValue(namedValue.Name, entity.Type.Properties.Single(p => p.Name == namedValue.Name).PropertyType.NullValue); }
/// <summary> /// Visits a <see cref="QueryEntityType"/>. /// </summary> /// <param name="type">Query type being visited.</param> /// <returns>The result of visiting this query type.</returns> public ComparisonResult Visit(QueryEntityType type) { return(this.parent.CompareStructural((QueryStructuralValue)this.expectedValue, this.actualValue, this.path, this.shouldThrow)); }
/// <summary> /// Generates a set of values for an entity type's key properties. Will throw if any key property is a dependent/foreign-key. For composite keys, only one of the values is guaranteed to be unique. /// </summary> /// <param name="type">The entity type to generate a key for</param> /// <returns>The key property values in metadata order</returns> protected internal IEnumerable<NamedValue> GeneratePropertyValuesWithUniqueKey(QueryEntityType type) { return this.GeneratePropertyValuesWithUniqueKey(type.EntitySet, type.EntityType); }