/// <summary> /// Store a collection of specified objects /// </summary> /// <param name="storableEnumerable">The objects collection to store.</param> /// <param name="forceUpdate">Update all children ignoring the <see cref="!:IStorable.IsChanged" /> flag.</param> /// <typeparam name="T">The type of the objects to store.</typeparam> public void Store <T> (IEnumerable <T> storableEnumerable, bool forceUpdate = false) where T : IStorable { List <T> newDBObjects = new List <T> (); lock (mutex) { bool success = db.RunInTransaction(() => { foreach (var t in storableEnumerable) { documentUpdated = false; try { var doc = db.GetExistingDocument(t.ID.ToString()); if (doc == null) { forceUpdate = true; newDBObjects.Add(t); } StorableNode node; ObjectChangedParser parser = new ObjectChangedParser(); parser.Parse(out node, t, Serializer.JsonSettings); if (!forceUpdate) { Update(node); } if (forceUpdate) { DocumentsSerializer.SaveObject(t, db, saveChildren: true); } if (t.ID != Info.ID && (forceUpdate || documentUpdated)) { Info.LastModified = DateTime.UtcNow; DocumentsSerializer.SaveObject(Info, db); } foreach (IStorable storable in node.OrphanChildren) { db.GetDocument(DocumentsSerializer.StringFromID(storable.ID, t.ID)).Delete(); } } catch (Exception ex) { Log.Exception(ex); return(false); } } return(true); }); if (!success) { throw new StorageException(Catalog.GetString("Error storing object from the storage")); } } foreach (var newObject in newDBObjects) { // FIXME: StorageDeletedEvent should use a collection instead of having to send one event per storable App.Current.EventsBroker.Publish(new StorageAddedEvent <T> { Object = newObject, Sender = this }); } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { IStorable storable = value as IStorable; if (context.SaveChildren && !context.Stack.Contains(value) && !context.Cache.IsCached(storable.ID)) { DocumentsSerializer.SaveObject(storable, context.DB, context); context.Cache.AddReference(storable); } writer.WriteValue(DocumentsSerializer.StringFromID(storable.ID, context.RootID)); }
/// <summary> /// Delete the specified collection of storable object from the database. /// If the object is configured to delete its children, we perform a bulk deletion of all the documents with /// the the storable.ID prefix, which is faster than parsing the object and it ensures that we don't leave /// orphaned documents in the DB /// </summary> /// <param name="storables">The objects to delete.</param> /// <typeparam name="T">The type of the object to delete.</typeparam> public void Delete <T> (IEnumerable <T> storables) where T : IStorable { lock (mutex) { bool success = db.RunInTransaction(() => { try { foreach (T storable in storables) { if (storable.DeleteChildren) { Query query = db.CreateAllDocumentsQuery(); // This should work, but raises an Exception in Couchbase.Lite //query.StartKey = t.ID; //query.EndKey = t.ID + "\uefff"; // In UTF-8, from all the possible values in a GUID string, '0' is the first char in the // list and 'f' would be the last one string sepchar = DocumentsSerializer.ID_SEP_CHAR.ToString(); query.StartKey = storable.ID + sepchar + "00000000-0000-0000-0000-000000000000"; query.EndKey = storable.ID + sepchar + "ffffffff-ffff-ffff-ffff-ffffffffffff"; query.InclusiveEnd = true; foreach (var row in query.Run()) { row.Document.Delete(); } } db.GetDocument(storable.ID.ToString()).Delete(); } return(true); } catch (Exception ex) { Log.Exception(ex); return(false); } }); if (success) { Info.LastModified = DateTime.UtcNow; DocumentsSerializer.SaveObject(Info, db, null, false); // FIXME: StorageDeletedEvent should use a collection instead of having to send one event per storable foreach (T storable in storables) { App.Current.EventsBroker.Publish(new StorageDeletedEvent <T> { Object = storable, Sender = this }); } } else { throw new StorageException(Catalog.GetString("Error deleting objects from the storage")); } } }
void Update(StorableNode node, SerializationContext context = null) { if (context == null) { context = new SerializationContext(db, node.Storable.GetType()); context.RootID = node.Storable.ID; } if (node.IsChanged) { documentUpdated = true; DocumentsSerializer.SaveObject(node.Storable, db, context, false); } /* Since we are saving single objects manually, we need to keep the stack * updated to avoid problems with circular references */ context.Stack.Push(node.Storable); foreach (StorableNode child in node.Children) { Update(child, context); } context.Stack.Pop(); }