/// <summary> /// Set new Id in entity class if entity needs one /// </summary> public virtual void SetAutoId(object entity, LiteEngine engine, string collection) { if (entity == null) { throw new ArgumentNullException("entity"); } if (engine == null) { throw new ArgumentNullException("engine"); } if (collection.IsNullOrWhiteSpace()) { throw new ArgumentNullException("collection"); } // if object is BsonDocument, add _id as ObjectId if (entity is BsonDocument) { var doc = entity as BsonDocument; if (!doc.RawValue.ContainsKey("_id")) { doc["_id"] = ObjectId.NewObjectId(); } return; } // get fields mapper var mapper = this.GetEntityMapper(entity.GetType()); var id = mapper.Id; // if not id or no autoId = true if (id == null || id.AutoId == false) { return; } AutoId autoId; if (_autoId.TryGetValue(id.DataType, out autoId)) { var value = id.Getter(entity); if (value == null || autoId.IsEmpty(value) == true) { var newId = autoId.NewId(engine, collection); id.Setter(entity, newId); } } }
public BsonMapper(Func <Type, object> customTypeInstantiator = null) { this.SerializeNullValues = false; this.TrimWhitespace = true; this.EmptyStringToNull = true; this.ResolveFieldName = (s) => s; this.ResolveMember = (t, mi, mm) => { }; this.ResolveCollectionName = (t) => Reflection.IsList(t) ? Reflection.GetListItemType(t).Name : t.Name; #if NET35 this.IncludeFields = false; #endif _typeInstantiator = customTypeInstantiator ?? Reflection.CreateInstance; #region Register CustomTypes RegisterType <Uri>(uri => uri.AbsoluteUri, bson => new Uri(bson.AsString)); RegisterType <DateTimeOffset>(value => new BsonValue(value.UtcDateTime), bson => bson.AsDateTime.ToUniversalTime()); RegisterType <TimeSpan>(value => new BsonValue(value.Ticks), bson => new TimeSpan(bson.AsInt64)); #endregion Register CustomTypes #region Register AutoId // register AutoId for ObjectId, Guid and Int32 RegisterAutoId ( value => value.Equals(ObjectId.Empty), (db, col) => ObjectId.NewObjectId() ); RegisterAutoId ( value => value == Guid.Empty, (db, col) => Guid.NewGuid() ); RegisterAutoId ( value => value == 0, (db, col) => { var max = db.Max(col, "_id"); return(max.IsMaxValue ? 1 : (max + 1)); } ); #endregion }
/// <summary> /// Internal implementation of insert a document /// </summary> private void InsertDocument(CollectionPage col, BsonDocument doc) { BsonValue id; // if no _id, add one as ObjectId if (!doc.RawValue.TryGetValue("_id", out id)) { doc["_id"] = id = ObjectId.NewObjectId(); } // test if _id is a valid type if (id.IsNull || id.IsMinValue || id.IsMaxValue) { throw LiteException.InvalidDataType("_id", id); } _log.Write(Logger.COMMAND, "insert document on '{0}' :: _id = {1}", col.CollectionName, id); // serialize object var bytes = BsonSerializer.Serialize(doc); // storage in data pages - returns dataBlock address var dataBlock = _data.Insert(col, bytes); // store id in a PK index [0 array] var pk = _indexer.AddNode(col.PK, id, null); // do link between index <-> data block pk.DataBlock = dataBlock.Position; // for each index, insert new IndexNode foreach (var index in col.GetIndexes(false)) { // for each index, get all keys (support now multi-key) - gets distinct values only // if index are unique, get single key only var keys = doc.GetValues(index.Field, index.Unique); // do a loop with all keys (multi-key supported) foreach (var key in keys) { // insert node var node = _indexer.AddNode(index, key, pk); // link my index node to data block address node.DataBlock = dataBlock.Position; } } }
/// <summary> /// Set new Id in entity class if entity needs one /// </summary> public void SetAutoId(T document) { // if object is BsonDocument, add _id as ObjectId if (document is BsonDocument) { var doc = document as BsonDocument; if (!doc.RawValue.ContainsKey("_id")) { doc["_id"] = ObjectId.NewObjectId(); } return; } // get fields mapper var mapper = _mapper.GetPropertyMapper(document.GetType()); // it's not best way because is scan all properties - but Id propably is first field :) var id = mapper.Select(x => x.Value).FirstOrDefault(x => x.FieldName == "_id"); // if not id or no autoId = true if (id == null || id.AutoId == false) { return; } // get id value var value = id.Getter(document); // test for ObjectId, Guid and Int32 types if (id.PropertyType == typeof(ObjectId) && (value == null || ObjectId.Empty.Equals((ObjectId)value))) { id.Setter(document, ObjectId.NewObjectId()); } else if (id.PropertyType == typeof(Guid) && Guid.Empty.Equals((Guid)value)) { id.Setter(document, Guid.NewGuid()); } else if (id.PropertyType == typeof(Int32) && ((Int32)value) == 0) { var max = this.Max(); id.Setter(document, max.IsMaxValue ? 1 : max + 1); } }
public BsonMapper() { this.SerializeNullValues = false; this.TrimWhitespace = true; this.EmptyStringToNull = true; this.ResolvePropertyName = (s) => s; #region Register CustomTypes RegisterType(uri => uri.AbsoluteUri, bson => new Uri(bson.AsString)); RegisterType <DateTimeOffset>(value => new BsonValue(value.UtcDateTime), bson => bson.AsDateTime.ToUniversalTime()); RegisterType <TimeSpan>(value => new BsonValue(value.Ticks), bson => new TimeSpan(bson.AsInt64)); #endregion Register CustomTypes #region Register AutoId // register AutoId for ObjectId, Guid and Int32 RegisterAutoId ( v => v.Equals(ObjectId.Empty), c => ObjectId.NewObjectId() ); RegisterAutoId ( v => v == Guid.Empty, c => Guid.NewGuid() ); RegisterAutoId ( v => v == 0, c => { var max = c.Max(); return(max.IsMaxValue ? 1 : (max + 1)); } ); #endregion }
/// <summary> /// Set new Id in entity class if entity needs one /// </summary> public void SetAutoId(object entity, LiteCollection <BsonDocument> col) { // if object is BsonDocument, add _id as ObjectId if (entity is BsonDocument) { var doc = entity as BsonDocument; if (!doc.RawValue.ContainsKey("_id")) { doc["_id"] = ObjectId.NewObjectId(); } return; } // get fields mapper var mapper = GetPropertyMapper(entity.GetType()); // it's not best way because is scan all properties - but Id propably is first field :) var id = mapper.Select(x => x.Value).FirstOrDefault(x => x.FieldName == "_id"); // if not id or no autoId = true if (id == null || id.AutoId == false) { return; } AutoId autoId; if (_autoId.TryGetValue(id.PropertyType, out autoId)) { var value = id.Getter(entity); if (value == null || autoId.IsEmpty(value) == true) { var newId = autoId.NewId(col); id.Setter(entity, newId); } } }
/// <summary> /// Set new Id in entity class if entity needs one /// </summary> public virtual void SetAutoId(object entity, LiteCollection <BsonDocument> col) { // if object is BsonDocument, add _id as ObjectId if (entity is BsonDocument) { var doc = entity as BsonDocument; if (!doc.RawValue.ContainsKey("_id")) { doc["_id"] = ObjectId.NewObjectId(); } return; } // get fields mapper var mapper = this.GetEntityMapper(entity.GetType()); var id = mapper.Id; // if not id or no autoId = true if (id == null || id.AutoId == false) { return; } AutoId autoId; if (_autoId.TryGetValue(id.DataType, out autoId)) { var value = id.Getter(entity); if (value == null || autoId.IsEmpty(value) == true) { var newId = autoId.NewId(col); id.Setter(entity, newId); } } }
public BsonMapper() { this.SerializeNullValues = false; this.TrimWhitespace = true; this.EmptyStringToNull = true; this.ResolvePropertyName = (s) => s; // register custom types this.RegisterType <Uri> ( serialize: (uri) => uri.AbsoluteUri, deserialize: (bson) => new Uri(bson.AsString) ); // register AutoId for ObjectId, Guid and Int32 this.RegisterAutoId <ObjectId> ( isEmpty: (v) => v.Equals(ObjectId.Empty), newId: (c) => ObjectId.NewObjectId() ); this.RegisterAutoId <Guid> ( isEmpty: (v) => v == Guid.Empty, newId: (c) => Guid.NewGuid() ); this.RegisterAutoId <Int32> ( isEmpty: (v) => v == 0, newId: (c) => { var max = c.Max(); return(max.IsMaxValue ? 1 : (max + 1)); } ); }
/// <summary> /// Create a new OBJECTID value /// </summary> public static IEnumerable <BsonValue> OBJECTID() { yield return(ObjectId.NewObjectId()); }
public static BsonValue OBJECTID() => ObjectId.NewObjectId();
/// <summary> /// Internal implementation of insert a document /// </summary> private void InsertDocument(CollectionPage col, BsonDocument doc, BsonType autoId) { // collection Sequence was created after release current datafile version. // In this case, Sequence will be 0 but already has documents. Let's fix this // ** this code can be removed when datafile change from 7 (HeaderPage.FILE_VERSION) ** if (col.Sequence == 0 && col.DocumentCount > 0) { var max = this.Max(col.CollectionName, "_id"); // if max value is a number, convert to Sequence last value // if not, just set sequence as document count col.Sequence = (max.IsInt32 || max.IsInt64 || max.IsDouble || max.IsDecimal) ? Convert.ToInt64(max.RawValue) : Convert.ToInt64(col.DocumentCount); } // increase collection sequence _id col.Sequence++; _pager.SetDirty(col); // if no _id, add one if (!doc.RawValue.TryGetValue("_id", out var id)) { doc["_id"] = id = autoId == BsonType.ObjectId ? new BsonValue(ObjectId.NewObjectId()) : autoId == BsonType.Guid ? new BsonValue(Guid.NewGuid()) : autoId == BsonType.DateTime ? new BsonValue(DateTime.Now) : autoId == BsonType.Int32 ? new BsonValue((Int32)col.Sequence) : autoId == BsonType.Int64 ? new BsonValue(col.Sequence) : BsonValue.Null; } // create bubble in sequence number if _id is bigger than current sequence else if (autoId == BsonType.Int32 || autoId == BsonType.Int64) { var current = id.AsInt64; // if current id is bigger than sequence, jump sequence to this number. Other was, do not increse sequnce col.Sequence = current >= col.Sequence ? current : col.Sequence - 1; } // test if _id is a valid type if (id.IsNull || id.IsMinValue || id.IsMaxValue) { throw LiteException.InvalidDataType("_id", id); } _log.Write(Logger.COMMAND, "insert document on '{0}' :: _id = {1}", col.CollectionName, id.RawValue); // serialize object var bytes = _bsonWriter.Serialize(doc); // storage in data pages - returns dataBlock address var dataBlock = _data.Insert(col, bytes); // store id in a PK index [0 array] var pk = _indexer.AddNode(col.PK, id, null); // do link between index <-> data block pk.DataBlock = dataBlock.Position; // for each index, insert new IndexNode foreach (var index in col.GetIndexes(false)) { // for each index, get all keys (support now multi-key) - gets distinct values only // if index are unique, get single key only var expr = new BsonExpression(index.Expression); var keys = expr.Execute(doc, true); // do a loop with all keys (multi-key supported) foreach (var key in keys) { // insert node var node = _indexer.AddNode(index, key, pk); // link my index node to data block address node.DataBlock = dataBlock.Position; } } }
public BsonMapper() { this.SerializeNullValues = false; this.TrimWhitespace = true; this.EmptyStringToNull = true; this.ResolvePropertyName = (s) => s; // register custom types this.RegisterType <Uri> ( serialize: (uri) => uri.AbsoluteUri, deserialize: (bson) => new Uri(bson.AsString) ); this.RegisterType <NameValueCollection> ( serialize: (nv) => { var doc = new BsonDocument(); foreach (var key in nv.AllKeys) { doc[key] = nv[key]; } return(doc); }, deserialize: (bson) => { var nv = new NameValueCollection(); var doc = bson.AsDocument; foreach (var key in doc.Keys) { nv[key] = doc[key].AsString; } return(nv); } ); // register AutoId for ObjectId, Guid and Int32 this.RegisterAutoId <ObjectId> ( isEmpty: (v) => v.Equals(ObjectId.Empty), newId: (c) => ObjectId.NewObjectId() ); this.RegisterAutoId <Guid> ( isEmpty: (v) => v == Guid.Empty, newId: (c) => Guid.NewGuid() ); this.RegisterAutoId <Int32> ( isEmpty: (v) => v == 0, newId: (c) => { var max = c.Max(); return(max.IsMaxValue ? 1 : (max + 1)); } ); }
/// <summary> /// Insert a new document to this collection. Document Id must be a new value in collection - Returns document Id /// </summary> public virtual BsonValue Insert(T document) { if (document == null) { throw new ArgumentNullException("document"); } this.Database.Mapper.SetAutoId(document, this.GetBsonCollection()); var doc = this.Database.Mapper.ToDocument(document); BsonValue id; // add ObjectId to _id if _id not found if (!doc.RawValue.TryGetValue("_id", out id)) { id = doc["_id"] = ObjectId.NewObjectId(); } // test if _id is a valid type if (id.IsNull || id.IsMinValue || id.IsMaxValue) { throw LiteException.InvalidDataType("_id", id); } // serialize object var bytes = BsonSerializer.Serialize(doc); this.Database.Transaction.Begin(); try { var col = this.GetCollectionPage(true); // storage in data pages - returns dataBlock address var dataBlock = this.Database.Data.Insert(col, bytes); // store id in a PK index [0 array] var pk = this.Database.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 foreach (var index in col.GetIndexes(false)) { var key = doc.Get(index.Field); var node = this.Database.Indexer.AddNode(index, key); // point my index to data object node.DataBlock = dataBlock.Position; // point my dataBlock dataBlock.IndexRef[index.Slot] = node.Position; } this.Database.Transaction.Commit(); return(id); } catch { this.Database.Transaction.Rollback(); throw; } }