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);
            }
        }
Beispiel #2
0
        /// <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;
        }
Beispiel #7
0
        /// <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);
        }
Beispiel #8
0
        /// <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));
        }
Beispiel #11
0
        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);
                        }
                    }
                }
            }
        }
Beispiel #16
0
        /// <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);
                }
            }
        }
Beispiel #18
0
        /// <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);
        }
Beispiel #19
0
        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());
        }
Beispiel #20
0
        /// <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);
        }
Beispiel #22
0
        /// <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);
            }
        }
Beispiel #24
0
        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);
                        }
                    }
                }
            }
        }
Beispiel #25
0
        /// <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));
        }
Beispiel #26
0
 /// <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));
 }
Beispiel #27
0
        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");
                        }
                    }
                }
            }
Beispiel #29
0
 /// <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);
        }
Beispiel #33
0
        /// <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()));
        }
Beispiel #34
0
        /// <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);
 }