/// <summary> /// Implements IDataInserter.AddAssociation by creating a PUT/POST $ref request using cross-referencing, and adds it to the batch /// </summary> /// <param name="parent">Update tree of parent, must have already been added using AddEntity</param> /// <param name="property">Navigation property for the association</param> /// <param name="child">Update tree of child, must have already been added using AddEntity</param> public void AddAssociation(KeyedResourceInstance parent, ResourceProperty property, KeyedResourceInstance child) { // determine which verb to use // RequestVerb verb; if (property.OtherAssociationEnd.Multiplicity == Multiplicity.Many) verb = RequestVerb.Post; else verb = RequestVerb.Put; // create the request // AstoriaRequest request = workspace.CreateRequest(); request.Verb = verb; // use content-id cross referencing to link them // string parentContentId = contentIDMap[parent]; string childContentId = contentIDMap[child]; request.URI = "$" + parentContentId + "/" + property.Name + "/$ref"; request.Payload = "<adsm:uri xmlns:adsm=\"http://docs.oasis-open.org/odata/ns/metadata\">$" + childContentId + "</adsm:uri>"; // add it to the queue // queue.Add(request); // fire the event // if (this.OnAddingAssociation != null) OnAddingAssociation(parent, property, child); }
/// <summary> /// Implements IDataInserter.AddEntity by creating a POST-based insert request and adding it to the batch queue /// </summary> /// <param name="key">Key expression for new entity</param> /// <param name="entity">Update tree for new entity</param> public void AddEntity(KeyExpression key, KeyedResourceInstance entity) { // build the request // ExpNode containerQuery = ContainmentUtil.BuildCanonicalQuery(key, true); AstoriaRequest request = workspace.CreateRequest(containerQuery, entity, RequestVerb.Post); // set ETagHeaderExpected appropriately if (key.ResourceType.Properties.Any(p => p.Facets.ConcurrencyModeFixed)) request.ETagHeaderExpected = true; // add it to the queue // queue.Add(request); // store the content-id // contentIDMap[entity] = request.Headers["Content-ID"]; // fire the event // if (this.OnAddingEntity != null) OnAddingEntity(key, entity); }
private void CreateEntryElement(KeyedResourceInstance keyedResourceInstance, XmlNode parentNode) { currentResource = keyedResourceInstance; XmlElement entryElement = CreateBasicEntryElement(keyedResourceInstance, parentNode); //string relativeParentKey = null; //Add the Id if there is one if (this.RequestVerb != RequestVerb.Post) { if (keyedResourceInstance.ResourceInstanceKey != null) { XmlElement idNode = CreateIdElement(keyedResourceInstance); entryElement.AppendChild(idNode); } } ResourceType type = Workspace.ServiceContainer.ResourceTypes.Single(rt => rt.Name == keyedResourceInstance.TypeName); XmlElement propertiesNode = CreateDataWebMetadataElement("properties"); IEnumerable<ResourceInstanceProperty> properties = keyedResourceInstance.Properties; if (this.RequestVerb == RequestVerb.Post && keyedResourceInstance.ResourceInstanceKey != null) properties = keyedResourceInstance.ResourceInstanceKey.KeyProperties.Union(properties); foreach (ResourceInstanceProperty property in properties) { if (property is ResourceInstanceSimpleProperty) { ResourceInstanceSimpleProperty simpleResourceProperty = property as ResourceInstanceSimpleProperty; VisitResourceInstanceSimpleProperty(simpleResourceProperty, propertiesNode); } else if (property is ResourceInstanceComplexProperty) { ResourceInstanceComplexProperty complexResourceProperty = property as ResourceInstanceComplexProperty; if (complexResourceProperty.ComplexResourceInstance == null) { VisitResourceInstanceComplexProperty(complexResourceProperty, propertiesNode); } else { VisitResourceInstanceComplexProperty(complexResourceProperty, propertiesNode); } } else if (property is ResourceInstanceNavProperty) { ResourceInstanceNavProperty navigationProperty = property as ResourceInstanceNavProperty; VisitResourceNavigationProperty(navigationProperty, entryElement); } } if (propertiesNode.ChildNodes.Count > 0) { if (!type.Facets.HasStream) { XmlElement contentNode = CreateAtomElement("content"); XmlAttribute contentTypeAttribute = CreateAtomAttribute("type"); contentTypeAttribute.Value = RequestUtil.RandomizeContentTypeCapitalization("application/xml"); contentNode.Attributes.Append(contentTypeAttribute); contentNode.AppendChild(propertiesNode); entryElement.AppendChild(contentNode); } else { entryElement.AppendChild(propertiesNode); } } if (EntryElementCallback != null) EntryElementCallback(entryElement); }
private bool CreateKeyedResourceInstance(ResourceContainer container, ResourceType resourceType, out KeyExpression key, out KeyedResourceInstance newResource) { int retryCount = 5; if (!_existingKeyMap.Keys.Contains(container)) _existingKeyMap.Add(container, new KeyExpressions()); newResource = resourceType.CreateRandomResource(container, new KeyExpressions(), false); // should not make request key = newResource.ResourceInstanceKey.CreateKeyExpression(container, resourceType); while (_existingKeyMap[container].Contains(key) && retryCount > 0) { newResource.ResourceInstanceKey = ResourceInstanceUtil.CreateUniqueKey(container, resourceType, new KeyExpressions(), new KeyExpressions()); key = newResource.ResourceInstanceKey.CreateKeyExpression(container, resourceType); retryCount--; } if (retryCount == 0) { newResource = null; key = null; return false; } _existingKeyMap[container].Add(key); _existingEntityMap[key] = newResource; return true; }
/// <summary> /// Implements IDataInserter.AddAssociation by generating the appropriate IUpdatable.AddReferenceToCollection or IUpdatable.SetReference call /// </summary> /// <param name="parent">Update tree of parent, must have already been added using AddEntity</param> /// <param name="property">Navigation property for the association</param> /// <param name="child">Update tree of child, must have already been added using AddEntity</param> public void AddAssociation(KeyedResourceInstance parent, ResourceProperty property, KeyedResourceInstance child) { // look up the object names for these entities // string parentObjectName = entityListName + "[" + entityIDs[parent] + "]"; string childObjectName = entityListName + "[" + entityIDs[child] + "]"; // code-gen the appropriate IUpdatable call // code.AppendLine("//Adding association"); if (property.OtherAssociationEnd.Multiplicity == Multiplicity.Many) code.AppendLine("updatable.AddReferenceToCollection(" + parentObjectName + ", \"" + property.Name + "\", " + childObjectName + ");"); else code.AppendLine("updatable.SetReference(" + parentObjectName + ", \"" + property.Name + "\", " + childObjectName + ");"); code.AppendLine(); // Fire the event // if (this.OnAddingAssociation != null) OnAddingAssociation(parent, property, child); // ensure that a later Flush/Close will write the SaveChanges call changesSaved = false; }
private string GetResourceType(KeyedResourceInstance e) { string resourceType = e.ResourceSetName; if (resourceType == null) resourceType = e.ResourceInstanceKey.ResourceSetName; return resourceType; }
private RowEntityType AddNewEntity(KeyedResourceInstance updateTree, ResourceType entityType) { List<RowEntityType> resourceList = _resources[updateTree.ResourceSetName]; RowEntityType newResource = new RowEntityType(updateTree.ResourceSetName, updateTree.TypeName); foreach (ResourceInstanceProperty keyProperty in updateTree.KeyProperties) { ResourceInstanceSimpleProperty tempProperty = (ResourceInstanceSimpleProperty)keyProperty; newResource.Properties.Add(tempProperty.Name, tempProperty.PropertyValue); } AddProperties(updateTree, newResource); if (entityType != null) AddNavigationProperties(entityType, newResource); resourceList.Add(newResource); return newResource; }
internal static KeyedResourceInstance CreateKeyedResourceInstanceByExactClone(ResourceContainer container, ResourceType resourceType, object dataObject) { List<ResourceInstanceProperty> properties = new List<ResourceInstanceProperty>(); List<ResourceInstanceProperty> keyProperties = new List<ResourceInstanceProperty>(); properties.AddRange(CloneObjectToResourceInstanceProperties(resourceType.Properties.OfType<ResourceProperty>().Where(rp => rp.PrimaryKey == null && rp.IsNavigation == false), dataObject)); keyProperties.AddRange(CloneObjectToResourceInstanceProperties(resourceType.Properties.OfType<ResourceProperty>().Where(rp => rp.PrimaryKey != null && rp.IsNavigation == false), dataObject)); ResourceInstanceKey key = new ResourceInstanceKey(container, resourceType, keyProperties.ToArray()); KeyedResourceInstance keyResourceInstance = new KeyedResourceInstance(key, properties.ToArray()); return keyResourceInstance; }
private void AddAssociation_Internal(KeyedResourceInstance parent, ResourceProperty property, KeyedResourceInstance child, bool addReverseLink) { bool changed; if (property.OtherAssociationEnd.Multiplicity == Multiplicity.Many) changed = AddEntityToCollection(child, FindRowInstance(parent), property.Name); else changed = UpdateLink(child, FindRowInstance(parent), property.Name); if (changed && addReverseLink && property.OtherSideNavigationProperty != null) AddAssociation_Internal(child, property.OtherSideNavigationProperty, parent, false); }
private void DataInserter_HandleAddingAssociation(KeyedResourceInstance parent, ResourceProperty property, KeyedResourceInstance child) { AddAssociation_Internal(parent, property, child, true); }
private void DataInserter_HandleAddingEntity(KeyExpression key, KeyedResourceInstance entity) { AddNewEntity(entity, key.ResourceType); }
private bool UpdateLink(KeyedResourceInstance updateTree, RowEntityType entityType, string linkProperty) { RowEntityType linkedEntity = FindRowInstance(updateTree); if (linkedEntity == null) throw new TestFailedException("Could not find row instance for updating link"); entityType.Properties[linkProperty] = linkedEntity; return true; }
private bool AddEntityToCollection(KeyedResourceInstance updateTree, RowEntityType entityType, string linkProperty) { RowEntityType linkedEntity = FindRowInstance(updateTree); if (linkedEntity == null) throw new TestFailedException("Could not find row instance for adding entity to collection"); //need to make sure its not already in the list List<RowEntityType> list = entityType.Properties[linkProperty] as List<RowEntityType>; if (list == null) entityType.Properties[linkProperty] = list = new List<RowEntityType>(); foreach (RowEntityType e in list) { // if its actually the same reference, then the keys must match if (e == linkedEntity) return false; // check the keys if its not the same reference bool match = true; foreach (ResourceInstanceSimpleProperty property in updateTree.KeyProperties) { object value; if (e.Properties.TryGetValue(property.Name, out value)) { if (value != property.PropertyValue) { match = false; break; } } } if (match) return false; } list.Add(linkedEntity); return true; }
public static AstoriaRequest BuildUpdate(Workspace workspace, KeyExpression modifiedKey, bool replace, HttpStatusCode expectedStatusCode, SerializationFormatKind format) { if (modifiedKey == null) return null; ResourceContainer container = modifiedKey.ResourceContainer; ResourceType resourceType = modifiedKey.ResourceType; if (replace && resourceType.Properties.Any(p => p.Facets.IsIdentity)) return null; string keyString = UriQueryBuilder.CreateKeyString(modifiedKey, false); if (expectedStatusCode == HttpStatusCode.NoContent && (keyString.Contains("/") || keyString.Contains(Uri.EscapeDataString("/")))) expectedStatusCode = HttpStatusCode.BadRequest; QueryNode query = ContainmentUtil.BuildCanonicalQuery(modifiedKey); List<ResourceInstanceProperty> properties = new List<ResourceInstanceProperty>(); string[] propertiesToSkip; //Skip because setting the birthdate to a random Datetime won't work due to contraints //if (resourceType.Name == "Employees") // propertiesToSkip = new string[] { "BirthDate" }; ////Skipping because it has some weird constraint on it //else if (resourceType.Name == "Order_Details") // propertiesToSkip = new string[] { "Discount" }; //else // propertiesToSkip = new string[] { }; foreach (ResourceProperty resourceProperty in resourceType.Properties.OfType<ResourceProperty>() .Where(p => !p.IsNavigation && p.PrimaryKey == null && !p.Facets.IsIdentity)) //&& !p.IsComplexType //&& !propertiesToSkip.Contains(p.Name))) { properties.Add(resourceProperty.CreateRandomResourceInstanceProperty()); } if (!properties.Any()) return null; KeyedResourceInstance resourceInstance = new KeyedResourceInstance( ResourceInstanceKey.ConstructResourceInstanceKey(modifiedKey), properties.ToArray()); AstoriaRequest request = workspace.CreateRequest(); request.Verb = replace ? RequestVerb.Put : RequestVerb.Patch; request.Query = query; request.UpdateTree = resourceInstance; request.ExpectedStatusCode = expectedStatusCode; request.Format = format; if (modifiedKey.ResourceType.Properties.Any(p => p.Facets.ConcurrencyModeFixed)) { request.Headers[ConcurrencyUtil.IfMatchHeader] = modifiedKey.ETag; request.ETagHeaderExpected = true; } return request; }
private RowEntityType FindRowInstance(KeyedResourceInstance updateTree) { return FindRowInstance(updateTree.ResourceSetName, updateTree.KeyProperties.OfType<ResourceInstanceSimpleProperty>().Select(p => p.Name).ToList(), updateTree.KeyProperties.OfType<ResourceInstanceSimpleProperty>().Select(p => p.PropertyValue).ToList()); }
public static KeyedResourceInstance CreateKeyedResourceInstanceByClone(ResourceContainer container, ResourceType resourceType, bool excludeRelationships) { Workspace workspace = container.Workspace; //Clone for an existing resource, and update its key KeyExpression keyExpression = workspace.GetRandomExistingKey(container, resourceType); if (keyExpression == null) return null; KeyedResourceInstance dataObject = workspace.GetSingleResourceByKey(keyExpression); if (dataObject == null) return null; ResourceInstanceKey key = null; // if there are any non-server-generated key properties, then we need to build the key if (keyExpression.ResourceType.Properties.Any(p => p.PrimaryKey != null && !p.Facets.ServerGenerated)) { ResourceType newResourceType = container.ResourceTypes.Where(rt => rt.Name == dataObject.TypeName).FirstOrDefault(); key = CreateUniqueKey(container, newResourceType); } //Foreach property in dataObject create a ResourceProperty List<ResourceInstanceProperty> properties = new List<ResourceInstanceProperty>(); properties.AddRange(dataObject.Properties.OfType<ResourceInstanceSimpleProperty>().ToArray()); properties.AddRange(dataObject.Properties.OfType<ResourceInstanceComplexProperty>().ToArray()); if (!excludeRelationships) properties.AddRange(CloneRequiredRelationships(container, keyExpression.ResourceType, keyExpression)); KeyedResourceInstance keyResourceInstance = null; if (key != null) keyResourceInstance = new KeyedResourceInstance(key, properties.ToArray()); else keyResourceInstance = new KeyedResourceInstance(dataObject.ResourceSetName, dataObject.TypeName, properties.ToArray()); return keyResourceInstance; }
private XmlElement CreateBasicEntryElement(KeyedResourceInstance keyedResourceInstance, XmlNode parentNode) { XmlElement entryElement = CreateAtomElement("entry"); if (parentNode == null) { AddNamespacesToTopElement(entryElement); document.AppendChild(entryElement); } else { parentNode.AppendChild(entryElement); } //add type attribute if (keyedResourceInstance.IncludeTypeMetadataHint) { string typeName = null; //if( this.Workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr ) // typeName = keyedResourceInstance.ResourceTypeName; //else typeName = this.Workspace.ContextNamespace + "." + keyedResourceInstance.TypeName; XmlElement typeElement = CreateAtomElement("category"); typeElement.SetAttribute("scheme", DataWebSchemeNamespace); typeElement.SetAttribute("term", typeName); entryElement.AppendChild(typeElement); } return entryElement; }
/// <summary> /// Implements IDataInserter.AddEntity by generating a IUpdatable.CreateResource call and multiple IUpdatable.SetValue calls /// </summary> /// <param name="key">Key expression for new entity</param> /// <param name="entity">Update tree for new entity</param> public void AddEntity(KeyExpression key, KeyedResourceInstance entity) { // generate a variable name for this entity and save it // int entityID = entityIDs.Count; entityIDs[entity] = entityID; string entityObjectName = "entity" + entityID; // code-gen the CreateResource and SetValue calls // code.AppendLine("//Adding entity"); foreach(string line in WriteObject(entityObjectName, entity)) code.AppendLine(line); code.AppendLine(entityListName + ".Add(" + entityObjectName + ");"); code.AppendLine(string.Empty); // Fire the event // if (this.OnAddingEntity != null) OnAddingEntity(key, entity); // ensure that a later Flush/Close will write the SaveChanges call changesSaved = false; }
private XmlElement CreateIdElement(KeyedResourceInstance keyedResourceInstance) { XmlElement idNode = CreateAtomElement("id"); idNode.InnerText = CreateCanonicalUri(keyedResourceInstance.ResourceInstanceKey); return idNode; }
private ResourceBodyTree CanonicalResourcePayload(Workspace workspace, ResourceContainer resourceContainer) { ResourceType type = resourceContainer.BaseType; // TODO: support PUT by adding key support. ResourceInstanceProperty[] keyProperties = new ResourceInstanceProperty[0]; ResourceInstanceKey keyExpression = new ResourceInstanceKey(resourceContainer,type, keyProperties); List<ResourceInstanceProperty> properties = new List<ResourceInstanceProperty>(); foreach (NodeProperty p in type.Properties) { // TODO: support to implement binding. if (p.Type is ResourceCollection) { continue; } if (p.Type is ComplexType) { continue; } properties.Add(new ResourceInstanceSimpleProperty(p.Name, p.GetSampleValue())); } KeyedResourceInstance instance = new KeyedResourceInstance(keyExpression, properties.ToArray()); return instance; }
public AstoriaRequest MakeMergeRequest(AstoriaRequest request, KeyedResourceInstance resourceInstance) { request.Verb = RequestVerb.Patch; request.ContentType = "application/atom+xml"; request.UpdateTree = resourceInstance; return request; }