private void CompareBagPropertyWithNullOrEmpty(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable <NamedValue> namedValues) { List <NamedValue> exactMatches = namedValues.Where(nv => nv.Name == propertyPath).ToList(); if (!exactMatches.Any()) { return; } ExceptionUtilities.Assert(exactMatches.Count == 1, "Should only find at most one property path {0} when looking for null or empty value", propertyPath); QueryCollectionValue actualQueryBagValue = instance.GetCollectionValue(memberProperty.Name); NamedValue expectedBagValue = exactMatches.Single(); if (expectedBagValue.Value == null) { this.WriteErrorIfNotNull(propertyPath, actualQueryBagValue); this.unusedNamedValuePaths.Remove(propertyPath); } else if (expectedBagValue.Value == EmptyData.Value) { if (!this.WriteErrorIfNull(propertyPath, actualQueryBagValue)) { this.WriteErrorIfNotEqual(propertyPath, actualQueryBagValue.Elements.Count, 0, "Expected zero elements in BagProperty"); this.unusedNamedValuePaths.Remove(propertyPath); } } }
/// <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 ComparePrimitiveBag(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable <NamedValue> namedValues) { int i = 0; var collection = instance.GetCollectionValue(memberProperty.Name); if (!this.WriteErrorIfNull(propertyPath, collection)) { List <NamedValue> primitiveItemNamedValues = namedValues.Where(pp => pp.Name == propertyPath + "." + i).ToList(); while (primitiveItemNamedValues.Any()) { if (i < collection.Elements.Count) { var scalarQueryValue = collection.Elements[i] as QueryScalarValue; ExceptionUtilities.Assert(primitiveItemNamedValues.Count() < 2, "Should not get more than one value for a primitive Bag item for path '{0}'", propertyPath + "." + i); var value = primitiveItemNamedValues.Single(); this.WriteErrorIfNotEqual(propertyPath, value.Value, scalarQueryValue); this.unusedNamedValuePaths.Remove(value.Name); } i++; primitiveItemNamedValues = namedValues.Where(pp => pp.Name == propertyPath + "." + i).ToList(); } this.WriteErrorIfNotEqual(propertyPath, collection.Elements.Count, i, "The number of expected items '{0}' does not match the actual '{1}' for propertyPath {2}", collection.Elements.Count, i, propertyPath); } }
private void SetCollectionProperty(QueryStructuralValue instance, QueryProperty memberProperty, List <QueryValue> collectionElements) { QueryCollectionValue queryCollectionValue = instance.GetCollectionValue(memberProperty.Name); queryCollectionValue.Elements.Clear(); foreach (QueryValue queryValue in collectionElements) { queryCollectionValue.Elements.Add(queryValue); } instance.SetValue(memberProperty.Name, queryCollectionValue); }
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); } }
private void FixupNavigationProperty(QueryStructuralValue fromValue, QueryStructuralValue toValue, string propertyName) { var propertyType = fromValue.Type.Properties.Where(p => p.Name == propertyName).Single().PropertyType; if (propertyType is QueryEntityType) { fromValue.SetValue(propertyName, toValue); } else { ExceptionUtilities.Assert(propertyType is QueryCollectionType, "Expecting collection type."); var currentCollection = fromValue.GetCollectionValue(propertyName); if (!currentCollection.Elements.Contains(toValue)) { currentCollection.Elements.Add(toValue); } fromValue.SetValue(propertyName, currentCollection); } }
/// <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 CompareComplexBag(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable <NamedValue> namedValues) { int i = 0; var collection = instance.GetCollectionValue(memberProperty.Name); if (!this.WriteErrorIfNull(propertyPath, collection)) { List <NamedValue> complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(propertyPath + "." + i + ".", StringComparison.Ordinal)).ToList(); while (complexInstanceNamedValues.Any()) { if (i < collection.Elements.Count) { var complexValue = collection.Elements[i] as QueryStructuralValue; this.CompareValues(complexValue, complexInstanceNamedValues, propertyPath + "." + i); } i++; complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(propertyPath + "." + i + ".", StringComparison.Ordinal)).ToList(); } this.WriteErrorIfNotEqual(propertyPath, collection.Elements.Count, i, "The number of expected items '{0}' does not match the actual '{1}' for propertyPath {2}", collection.Elements.Count, i, propertyPath); } }
private void CompareBagPropertyWithNullOrEmpty(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable<NamedValue> namedValues) { List<NamedValue> exactMatches = namedValues.Where(nv => nv.Name == propertyPath).ToList(); if (!exactMatches.Any()) { return; } ExceptionUtilities.Assert(exactMatches.Count == 1, "Should only find at most one property path {0} when looking for null or empty value", propertyPath); QueryCollectionValue actualQueryBagValue = instance.GetCollectionValue(memberProperty.Name); NamedValue expectedBagValue = exactMatches.Single(); if (expectedBagValue.Value == null) { this.WriteErrorIfNotNull(propertyPath, actualQueryBagValue); this.unusedNamedValuePaths.Remove(propertyPath); } else if (expectedBagValue.Value == EmptyData.Value) { if (!this.WriteErrorIfNull(propertyPath, actualQueryBagValue)) { this.WriteErrorIfNotEqual(propertyPath, actualQueryBagValue.Elements.Count, 0, "Expected zero elements in BagProperty"); this.unusedNamedValuePaths.Remove(propertyPath); } } }
private void ComparePrimitiveBag(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable<NamedValue> namedValues) { int i = 0; var collection = instance.GetCollectionValue(memberProperty.Name); if (!this.WriteErrorIfNull(propertyPath, collection)) { List<NamedValue> primitiveItemNamedValues = namedValues.Where(pp => pp.Name == propertyPath + "." + i).ToList(); while (primitiveItemNamedValues.Any()) { if (i < collection.Elements.Count) { var scalarQueryValue = collection.Elements[i] as QueryScalarValue; ExceptionUtilities.Assert(primitiveItemNamedValues.Count() < 2, "Should not get more than one value for a primitive Bag item for path '{0}'", propertyPath + "." + i); var value = primitiveItemNamedValues.Single(); this.WriteErrorIfNotEqual(propertyPath, value.Value, scalarQueryValue); this.unusedNamedValuePaths.Remove(value.Name); } i++; primitiveItemNamedValues = namedValues.Where(pp => pp.Name == propertyPath + "." + i).ToList(); } this.WriteErrorIfNotEqual(propertyPath, collection.Elements.Count, i, "The number of expected items '{0}' does not match the actual '{1}' for propertyPath {2}", collection.Elements.Count, i, propertyPath); } }
private void CompareComplexBag(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable<NamedValue> namedValues) { int i = 0; var collection = instance.GetCollectionValue(memberProperty.Name); if (!this.WriteErrorIfNull(propertyPath, collection)) { List<NamedValue> complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(propertyPath + "." + i + ".", StringComparison.Ordinal)).ToList(); while (complexInstanceNamedValues.Any()) { if (i < collection.Elements.Count) { var complexValue = collection.Elements[i] as QueryStructuralValue; this.CompareValues(complexValue, complexInstanceNamedValues, propertyPath + "." + i); } i++; complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(propertyPath + "." + i + ".", StringComparison.Ordinal)).ToList(); } this.WriteErrorIfNotEqual(propertyPath, collection.Elements.Count, i, "The number of expected items '{0}' does not match the actual '{1}' for propertyPath {2}", collection.Elements.Count, i, propertyPath); } }
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); }
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; }
private void SetCollectionProperty(QueryStructuralValue instance, QueryProperty memberProperty, List<QueryValue> collectionElements) { QueryCollectionValue queryCollectionValue = instance.GetCollectionValue(memberProperty.Name); queryCollectionValue.Elements.Clear(); foreach (QueryValue queryValue in collectionElements) { queryCollectionValue.Elements.Add(queryValue); } instance.SetValue(memberProperty.Name, queryCollectionValue); }