/// <summary> /// Create a new permanent index in all documents inside this collections if index not exists already. Returns true if index was created or false if already exits /// </summary> /// <param name="field">Document field name (case sensitive)</param> /// <param name="unique">Create a unique values index?</param> public virtual bool EnsureIndex(string field, bool unique = false) { if (string.IsNullOrEmpty(field)) { throw new ArgumentNullException("field"); } if (!Regex.IsMatch(field, CollectionIndex.FIELD_PATTERN) || field.Length > CollectionIndex.FIELD_MAX_LENGTH) { throw new LiteException("Invalid field format."); } if (typeof(T) != typeof(BsonDocument) && typeof(T).GetProperty(field) == null) { throw new LiteException(string.Format("Property name {0} not found in {1} class", field, typeof(T).Name)); } // do not create collection at this point var col = this.GetCollectionPage(false); // check if index already exists (collection must exists) if (col != null && col.Indexes.FirstOrDefault(x => x.Field.Equals(field, StringComparison.InvariantCultureIgnoreCase)) != null) { return(false); } ; // start transaction _engine.Transaction.Begin(); try { // if not collection yet, create a new now if (col == null) { col = _engine.Collections.Add(this.Name); _pageID = col.PageID; } // get index slot var slot = col.GetFreeIndex(); // create index head var index = _engine.Indexer.CreateIndex(col.Indexes[slot]); index.Field = field; index.Unique = unique; // read all objects (read from PK index) foreach (var node in _engine.Indexer.FindAll(col.PK)) { var dataBlock = _engine.Data.Read(node.DataBlock, true); // read object var doc = BsonSerializer.Deserialize <T>(dataBlock.Key, dataBlock.Buffer); // adding index var key = BsonSerializer.GetFieldValue(doc, field); var newNode = _engine.Indexer.AddNode(index, key); // adding this new index Node to indexRef dataBlock.IndexRef[slot] = newNode.Position; // link index node to datablock newNode.DataBlock = dataBlock.Position; // mark datablock page as dirty dataBlock.Page.IsDirty = true; } _engine.Transaction.Commit(); } catch (Exception ex) { _engine.Transaction.Rollback(); throw ex; } return(true); }
/// <summary> /// Update a document in this collection. Returns false if not found document in collection /// </summary> public virtual bool Update(T doc) { if (doc == null) { throw new ArgumentNullException("doc"); } // gets document Id var id = BsonSerializer.GetIdValue(doc); if (id == null) { throw new LiteException("Document Id can't be null"); } // serialize object var bytes = BsonSerializer.Serialize(doc); // start transaction _engine.Transaction.Begin(); try { var col = this.GetCollectionPage(false); // if no collection, no updates if (col == null) { _engine.Transaction.Abort(); return(false); } // find indexNode from pk index var indexNode = _engine.Indexer.FindOne(col.PK, id); // if not found document, no updates if (indexNode == null) { _engine.Transaction.Abort(); return(false); } // update data storage var dataBlock = _engine.Data.Update(col, indexNode.DataBlock, bytes); // delete/insert indexes - do not touch on PK for (byte i = 1; i < col.Indexes.Length; i++) { var index = col.Indexes[i]; if (!index.IsEmpty) { var key = BsonSerializer.GetFieldValue(doc, index.Field); var node = _engine.Indexer.GetNode(dataBlock.IndexRef[i]); // check if my index node was changed if (node.Key.CompareTo(new IndexKey(key)) != 0) { // remove old index node _engine.Indexer.Delete(index, node.Position); // and add a new one var newNode = _engine.Indexer.AddNode(index, key); // point my index to data object newNode.DataBlock = dataBlock.Position; // point my dataBlock dataBlock.IndexRef[i] = newNode.Position; dataBlock.Page.IsDirty = true; } } } _engine.Transaction.Commit(); return(true); } catch (Exception ex) { _engine.Transaction.Rollback(); throw ex; } }
/// <summary> /// Insert a new document to this collection. Document Id must be a new value in collection /// </summary> public virtual void Insert(T doc) { if (doc == null) { throw new ArgumentNullException("doc"); } // gets document Id var id = BsonSerializer.GetIdValue(doc); if (id == null) { throw new LiteException("Document Id can't be null"); } // serialize object var bytes = BsonSerializer.Serialize(doc); _engine.Transaction.Begin(); try { var col = this.GetCollectionPage(true); // storage in data pages - returns dataBlock address var dataBlock = _engine.Data.Insert(col, new IndexKey(id), bytes); // store id in a PK index [0 array] var pk = _engine.Indexer.AddNode(col.PK, id); // do links between index <-> data block pk.DataBlock = dataBlock.Position; dataBlock.IndexRef[0] = pk.Position; // for each index, insert new IndexNode for (byte i = 1; i < col.Indexes.Length; i++) { var index = col.Indexes[i]; if (!index.IsEmpty) { var key = BsonSerializer.GetFieldValue(doc, index.Field); var node = _engine.Indexer.AddNode(index, key); // point my index to data object node.DataBlock = dataBlock.Position; // point my dataBlock dataBlock.IndexRef[i] = node.Position; } } _engine.Transaction.Commit(); } catch (Exception ex) { _engine.Transaction.Rollback(); throw ex; } }