public KeyExpression(ResourceContainer container, ResourceType resourceType, IDictionary <string, object> properties) : base(null) { // populate key and ETag from properties List <NodeProperty> keyProperties = resourceType.Key.Properties.ToList(); _properties = new PropertyExpression[keyProperties.Count]; _values = new ConstantExpression[keyProperties.Count]; _include = new bool[keyProperties.Count]; _resourceType = resourceType; _resourceContainer = container; // originally, this would not happen if using constructor without type for (int i = 0; i < keyProperties.Count; i++) { NodeProperty property = keyProperties[i]; _properties[i] = new PropertyExpression(property); _values[i] = new ConstantExpression(new NodeValue(properties[property.Name], property.Type)); _include[i] = true; } if (resourceType.Properties.Any(p => p.Facets.ConcurrencyModeFixed)) { ETag = ConcurrencyUtil.ConstructETag(container, properties); } else { ETag = null; } this.KnownPropertyValues = properties; }
protected override void Verify() { if (!Applies(Response)) { return; } // build a common payload for the insert // CommonPayload insertPayload = Response.Request.CommonPayload; // get the entity that was inserted PayloadObject inserted; if (!TryGetSingleObjectFromPayload(insertPayload, out inserted)) { ResponseVerification.LogFailure(Response, new Exception("Insert request payload did not contain a single entity")); } // determine the type based on what was inserted ResourceType type = Response.Workspace.ServiceContainer.ResourceTypes.Single(rt => inserted.Type.Equals(rt.Namespace + "." + rt.Name)); // get the entity that was returned PayloadObject returned; if (!TryGetSingleObjectFromPayload(Response.CommonPayload, out returned)) { if (Versioning.Server.SupportsLiveFeatures) { string preferHeader; if (Response.Request.Headers.TryGetValue("prefer", out preferHeader) && preferHeader == "return=minimal") { return; } } ResponseVerification.LogFailure(Response, new Exception("Insert response payload did not contain a single entity")); } // verify that the inserted and returned entities are equivalent VerifyInsertResponse(type, inserted, returned); // re-query the entity Workspace workspace = Response.Workspace; AstoriaRequest queryRequest = workspace.CreateRequest(); if (type.Properties.Any(p => p.Facets.ConcurrencyModeFixed)) { queryRequest.ETagHeaderExpected = true; } if (type.Key.Properties.Any(p => p.Type == Clr.Types.DateTime)) { // this will blow up for MEST, but we don't currently have any datetime key + MEST types ResourceContainer container = Response.Workspace.ServiceContainer.ResourceContainers.Single(rc => !(rc is ServiceOperation) && rc.ResourceTypes.Contains(type)); queryRequest.Query = ContainmentUtil.BuildCanonicalQuery(ConcurrencyUtil.ConstructKey(container, returned)); } else { queryRequest.URI = Uri.UnescapeDataString(returned.AbsoluteUri); if (queryRequest.URI.Contains("E+")) { queryRequest.URI = queryRequest.URI.Replace("E+", "E"); } if (queryRequest.URI.Contains("e+")) { queryRequest.URI = queryRequest.URI.Replace("e+", "e"); } } AstoriaResponse queryResponse = queryRequest.GetResponse(); if (queryResponse.ActualStatusCode == HttpStatusCode.BadRequest) { // try it as a filter instead (possibly caused by the URI being too long) // this will blow up for MEST ResourceContainer container = Response.Workspace.ServiceContainer.ResourceContainers .Single(rc => !(rc is ServiceOperation) && rc.ResourceTypes.Contains(type)); KeyExpression key = ConcurrencyUtil.ConstructKey(container, returned); queryRequest = workspace.CreateRequest(Query.From(Exp.Variable(container)).Where(key.Predicate)); queryResponse = queryRequest.GetResponse(); } queryResponse.Verify(); // get the entity from the query PayloadObject queried; if (!TryGetSingleObjectFromPayload(queryResponse.CommonPayload, out queried)) { ResponseVerification.LogFailure(queryResponse, new Exception("Query response payload did not contain a single entity")); } // ensure that the entity did not change between the insert and the re-query VerifyQueryResponse(type, returned, queried); }