public async Task<SaveResult> SaveChanges(IEnumerable<IEntity> entitiesToSave, SaveOptions saveOptions) { var entityManager = entitiesToSave.First().EntityAspect.EntityManager; var saveBundleNode = PrepareSaveBundle(entitiesToSave, saveOptions); try { var saveResultJson = await saveOptions.DataService.PostAsync(saveOptions.ResourceName, saveBundleNode.Serialize()); var jn = JNode.DeserializeFrom(saveResultJson); if (jn.HasValues("Errors") || jn.HasValues("errors")) { throw new SaveException(entityManager, jn); } return ProcessSaveResult(entityManager, saveOptions, jn); } catch (DataServiceRequestException dsre) { var jn = JNode.DeserializeFrom(dsre.ResponseContent); throw new SaveException(entityManager, jn); } catch (HttpRequestException e) { throw new SaveException(e.Message, e); } }
private SaveResult ProcessSaveResult(EntityManager entityManager, SaveOptions saveOptions, string saveResultJson) { var jo = JObject.Parse(saveResultJson); var jn = new JNode(jo); var kms = jn.GetArray <KeyMapping>("KeyMappings"); var keyMappings = kms.Select(km => ToEntityKeys(km)).ToDictionary(tpl => tpl.Item1, tpl => tpl.Item2); using (entityManager.NewIsLoadingBlock(false)) { keyMappings.ForEach(km => { var targetEntity = entityManager.GetEntityByKey(km.Key); targetEntity.EntityAspect.SetDpValue(km.Key.EntityType.KeyProperties[0], km.Value.Values[0]); }); var prop = jo.Property("Entities"); if (prop == null) { return(null); } var entityNodes = (JArray)prop.Value; var serializer = new JsonSerializer(); var mappingContext = new MappingContext() { EntityManager = entityManager, MergeStrategy = MergeStrategy.OverwriteChanges, LoadingOperation = LoadingOperation.Save, JsonResultsAdapter = saveOptions.DataService.JsonResultsAdapter }; var jsonConverter = new JsonEntityConverter(mappingContext); serializer.Converters.Add(jsonConverter); // Don't use the result of the Deserialize call to get the list of entities // because it won't include entities added on the server. serializer.Deserialize <IEnumerable <IEntity> >(entityNodes.CreateReader()); var allEntities = mappingContext.Entities; allEntities.ForEach(e => e.EntityAspect.AcceptChanges()); return(new SaveResult(allEntities, keyMappings)); } }
private JNode PrepareSaveBundle(IEnumerable<IEntity> entitiesToSave, SaveOptions saveOptions) { var jn = new JNode(); jn.AddArray("entities", entitiesToSave.Select(e => EntityToJNode(e))); jn.AddJNode("saveOptions", saveOptions); return jn; }
private SaveResult ProcessSaveResult(EntityManager entityManager, SaveOptions saveOptions, JNode jNode) { var kms = jNode.GetArray<KeyMapping>("KeyMappings"); var keyMappings = kms.Select(km => ToEntityKeys(km, entityManager.MetadataStore)).ToDictionary(tpl => tpl.Item1, tpl => tpl.Item2); using (entityManager.NewIsLoadingBlock(false)) { keyMappings.ForEach(km => { var targetEntity = entityManager.GetEntityByKey(km.Key); targetEntity.EntityAspect.SetDpValue(km.Key.EntityType.KeyProperties[0], km.Value.Values[0]); }); var entityNodes = jNode.GetToken<JArray>("Entities"); var serializer = new JsonSerializer(); var mappingContext = new MappingContext() { EntityManager = entityManager, MergeStrategy = MergeStrategy.OverwriteChanges, LoadingOperation = LoadingOperation.Save, JsonResultsAdapter = saveOptions.DataService.JsonResultsAdapter }; var jsonConverter = new JsonEntityConverter(mappingContext); serializer.Converters.Add(jsonConverter); // serializer.Converters.Add(new StringEnumConverter()); // Don't use the result of the Deserialize call to get the list of entities // because it won't include entities added on the server. serializer.Deserialize<IEnumerable<IEntity>>(entityNodes.CreateReader()); var allEntities = mappingContext.Entities; allEntities.ForEach(e => e.EntityAspect.AcceptChanges()); return new SaveResult(allEntities, keyMappings); } }
public SaveOptions(SaveOptions saveOptions) { ResourceName = saveOptions.ResourceName; DataService = saveOptions.DataService; Tag = saveOptions.Tag; }
public async Task <SaveResult> SaveChanges(IEnumerable <IEntity> entitiesToSave, SaveOptions saveOptions) { var entityManager = entitiesToSave.First().EntityAspect.EntityManager; var saveBundleNode = PrepareSaveBundle(entitiesToSave, saveOptions); try { var saveResultJson = await saveOptions.DataService.PostAsync(saveOptions.ResourceName, saveBundleNode.Serialize()); var jn = JNode.DeserializeFrom(saveResultJson); if (jn.HasValues("Errors") || jn.HasValues("errors")) { throw new SaveException(entityManager, jn); } return(ProcessSaveResult(entityManager, saveOptions, jn)); } catch (DataServiceRequestException dsre) { var jn = JNode.DeserializeFrom(dsre.ResponseContent); throw new SaveException(entityManager, jn); } catch (HttpRequestException e) { throw new SaveException(e.Message, e); } }
public async Task SaveWithEntityErrorsException() { var em1 = await TestFns.NewEm(_serviceName); // ok(true, "Skipped test - OData does not support server interception or alt resources"); // ok(true, "Skipped test - Mongo does not YET support server side validation"); var twoCusts = CreateParentAndChildren(em1); var so = new SaveOptions("SaveWithEntityErrorsException", tag: "entityErrorsException"); try { var sr0 = await em1.SaveChanges(so); Assert.Fail("should not get here"); } catch (SaveException e) { Assert.IsTrue(e.EntityErrors.Count == 2, "should have two errors"); var order1 = twoCusts.Cust1.Orders[0]; Assert.IsTrue(order1.EntityAspect.ValidationErrors.Count == 1); var order2 = twoCusts.Cust1.Orders[1]; Assert.IsTrue(order2.EntityAspect.ValidationErrors.Count == 1); Assert.IsTrue(order2.EntityAspect.ValidationErrors.First().Context.PropertyPath == "OrderID"); } catch (Exception e) { Assert.Fail("should not get here - wrong exception" + e.Message); } // now save it properly var sr1 = await em1.SaveChanges(); Assert.IsTrue(sr1.Entities.Count == 4); }
public async Task SaveWithServerExit() { var em1 = await TestFns.NewEm(_serviceName); // ok(true, "Skipped test - OData does not support server interception or alt resources"); CreateParentAndChildren(em1); var so = new SaveOptions("SaveWithExit", tag: "exit"); var sr0 = await em1.SaveChanges(so); Assert.IsTrue(sr0.Entities.Count == 0); }
public async Task CaptureAddlSavesDoneOnServer() { var em1 = await TestFns.NewEm(_serviceName); // ok(true, "Skipped test - OData does not support server interception or alt resources"); // ok(true, "N/A for Mongo - test not yet implemented - requires server side async call"); var q = new EntityQuery<Category>().Where(c => c.CategoryName.StartsWith("Beverage")).Expand("Products"); var r = await q.Execute(em1); var category = r.First(); var products = category.Products; var prices = products.Select(p => p.UnitPrice).ToList(); category.CategoryName = TestFns.MorphString(category.CategoryName); var so = new SaveOptions(tag: "increaseProductPrice"); var sr = await em1.SaveChanges(null, so); Assert.IsTrue(sr.Entities.Count == 13, "should have saved 13 entities + 1 category + 12 products"); Assert.IsTrue(sr.Entities.OfType<Product>().Count() == 12, "should be 12 products"); var ek = category.EntityAspect.EntityKey; var em2 = new EntityManager(em1); var r2 = await em2.ExecuteQuery(ek.ToQuery<Category>().Expand("Products")); var cat2 = r2.First(); var products2 = cat2.Products; var newPrices = products2.Select(p => p.UnitPrice).ToList(); Assert.IsTrue(!prices.SequenceEqual(newPrices), "prices should have changed"); }
public async Task ExceptionThrownOnServer() { var em1 = await TestFns.NewEm(_serviceName); // ok(true, "Skipped test - OData does not support server interception or alt resources"); var q = new EntityQuery<Order>().Take(1); var orders = await em1.ExecuteQuery(q); var order = orders.First(); order.Freight = order.Freight + .5m; var so = new SaveOptions("SaveAndThrow", tag: "SaveAndThrow"); try { var sr = await em1.SaveChanges(null, so); Assert.Fail("should not get here"); } catch (SaveException se) { Assert.IsTrue(se.Message.Contains("Deliberately thrown"), "message should be correct"); } }