예제 #1
0
        /// <summary>
        /// Removes the the entity with the given key from the given the given property on the given structural value
        /// </summary>
        /// <param name="keyToRemove">The key of the entity to remove</param>
        /// <param name="related">The structural value to remove from</param>
        /// <param name="navigation">The property to remove from</param>
        private void RemoveFromNavigationProperty(EntityDataKey keyToRemove, QueryStructuralValue related, NavigationProperty navigation)
        {
            if (navigation.ToAssociationEnd.Multiplicity == EndMultiplicity.Many)
            {
                var collection = related.GetCollectionValue(navigation.Name);

                // remove the element with the given key from the collection, if it is present
                foreach (var element in collection.Elements.Cast <QueryStructuralValue>().ToList())
                {
                    if (this.GetEntityKey(element).Equals(keyToRemove))
                    {
                        collection.Elements.Remove(element);
                    }
                }
            }
            else
            {
                // if the value's key matches, set it to null
                var value = related.GetStructuralValue(navigation.Name);
                if (!value.IsNull && this.GetEntityKey(value).Equals(keyToRemove))
                {
                    related.SetValue(navigation.Name, value.Type.NullValue);
                }
            }
        }
        private void ExpandRelated(Dictionary<QueryStructuralValue, QueryStructuralValue> identityMap, QueryValue item, string[] splitPath, int position, IEnumerable<string> expandedPath, IEnumerable<string> selectedPath)
        {
            QueryStructuralValue qsv = item as QueryStructuralValue;
            if (qsv == null)
            {
                return;
            }

            if (position >= splitPath.Length)
            {
                return;
            }

            var memberName = splitPath[position];
            var member = qsv.Type.Properties.SingleOrDefault(c => c.Name == memberName);
            if (member == null)
            {
                return;
            }

            // do not expand if the selected paths don't contain the expand value
            if (selectedPath.Count() > 0 && !selectedPath.Contains(member.Name))
            {
                return;
            }

            var clone = this.CloneStructuralValue(identityMap, qsv);

            if (member.PropertyType is QueryCollectionType)
            {
                var oldValue = qsv.GetCollectionValue(memberName);

                clone.SetValue(memberName, this.CloneCollectionValue(identityMap, oldValue));
                if (!oldValue.IsNull)
                {
                    foreach (var e in oldValue.Elements)
                    {
                        this.ExpandRelated(identityMap, e, splitPath, position + 1, expandedPath, selectedPath);
                    }
                }
            }
            else if (member.PropertyType is QueryStructuralType)
            {
                var oldValue = qsv.GetStructuralValue(memberName);
                var newValue = this.CloneStructuralValue(identityMap, oldValue);
                clone.SetValue(memberName, newValue);
                this.ExpandRelated(identityMap, oldValue, splitPath, position + 1, expandedPath, selectedPath);
            }
        }
예제 #3
0
        private void FixupReferencesOfVisibleEntity(QueryStructuralValue originalEntity, QueryStructuralValue visibleEntity)
        {
            foreach (var property in originalEntity.Type.Properties)
            {
                var entityProperty = property.PropertyType as QueryEntityType;
                if (entityProperty != null)
                {
                    var originalProperty = originalEntity.GetStructuralValue(property.Name);
                    QueryStructuralValue fixedUpProperty;
                    if (!this.VisibleEntitiesGraph.TryGetValue(originalProperty, out fixedUpProperty))
                    {
                        fixedUpProperty = entityProperty.NullValue;
                    }

                    var navigationProperty = ((QueryEntityType)visibleEntity.Type).EntityType.AllNavigationProperties.Where(p => p.Name == property.Name).SingleOrDefault();
                    ExceptionUtilities.CheckObjectNotNull(navigationProperty, "Could not find navigation property '" + property.Name + "' on entity.");

                    this.FixupBothEndsOfNavigationProperty(visibleEntity, fixedUpProperty, navigationProperty);
                }
            }
        }
예제 #4
0
        /// <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);
                        }
                    }
                }
            }
        }
        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);
                        }
                    }
                }
            }
        }
예제 #6
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);
                        }
                    }
                }
            }
        }
        private QueryStructuralValue CloneStructuralValue(Dictionary<QueryStructuralValue, QueryStructuralValue> identityMap, QueryStructuralValue qsv)
        {
            if (qsv.IsNull)
            {
                return qsv;
            }

            QueryStructuralValue clonedValue;

            if (identityMap.TryGetValue(qsv, out clonedValue))
            {
                return clonedValue;
            }

            clonedValue = qsv.Type.CreateNewInstance();
            identityMap.Add(qsv, clonedValue);
      
            foreach (var m in qsv.Type.Properties)
            {
                // copy scalar properties
                if (m.PropertyType is QueryScalarType)
                {
                    clonedValue.SetValue(m.Name, qsv.GetScalarValue(m.Name));
                    continue;
                }

                // copy stream properties
                if (m.PropertyType is AstoriaQueryStreamType)
                {
                    if (m.Name.Contains("DefaultStream"))
                    {
                        clonedValue.SetDefaultStreamValue(qsv.GetDefaultStreamValue());
                    }
                    else
                    {
                        clonedValue.SetStreamValue(m.Name, qsv.GetStreamValue(m.Name));
                    }

                    continue;
                }

                var qst = m.PropertyType as QueryStructuralType;
                if (m.PropertyType is QueryStructuralType)
                {
                    if (!qst.IsValueType)
                    {
                        // skip reference types, clone everything else
                        continue;
                    }

                    clonedValue.SetValue(m.Name, this.CloneStructuralValue(identityMap, qsv.GetStructuralValue(m.Name)));
                }

                var qct = m.PropertyType as QueryCollectionType;
                if (qct != null)
                {
                    var elementStructuralType = qct.ElementType as QueryStructuralType;
                    if (elementStructuralType != null)
                    {
                        if (!elementStructuralType.IsValueType)
                        {
                            // skip collections of reference types, clone everything else
                            continue;
                        }
                    }

                    clonedValue.SetValue(m.Name, this.CloneCollectionValue(identityMap, qsv.GetCollectionValue(m.Name)));
                }
            }

            return clonedValue;
        }
예제 #8
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);
                        }
                    }
                }
            }
        }
        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);
                        }
                    }
                }
            }
        }