public LiteCollection(string name, LazyLoad <LiteEngine> engine, BsonMapper mapper, Logger log) { _name = name ?? mapper.ResolveCollectionName(typeof(T)); _engine = engine; _mapper = mapper; _log = log; _visitor = new QueryVisitor <T>(mapper); _includes = new List <string>(); // if strong typed collection, get _id member mapped (if exists) if (typeof(T) != typeof(BsonDocument)) { var entity = mapper.GetEntityMapper(typeof(T)); _id = entity.Id; if (_id != null && _id.AutoId) { _autoId = _id.DataType == typeof(ObjectId) ? BsonType.ObjectId : _id.DataType == typeof(Guid) ? BsonType.Guid : _id.DataType == typeof(DateTime) ? BsonType.DateTime : _id.DataType == typeof(Int32) ? BsonType.Int32 : _id.DataType == typeof(Int64) ? BsonType.Int64 : BsonType.Null; } } else { _autoId = BsonType.ObjectId; } }
/// <summary> /// Based on a LINQ expression, returns document field mapped from class Property. /// Support multi level dotted notation: x => x.Customer.Name /// Prefix is used on array expression like: x => x.Customers.Any(z => z.Name == "John") /// </summary> public string GetField(Expression expr, string prefix = "", bool showArrayItems = false) { var property = prefix + expr.GetPath(); var parts = property.Split('.'); var fields = new string[parts.Length]; var type = _type; var isdbref = false; // loop "first.second.last" for (var i = 0; i < parts.Length; i++) { var entity = _mapper.GetEntityMapper(type); var part = parts[i]; var prop = entity.Members.Find(x => x.MemberName == part); if (prop == null) { throw new NotSupportedException(property + " not mapped in " + type.Name); } // if property is an IEnumerable, gets underlying type (otherwise, gets PropertyType) type = prop.UnderlyingType; fields[i] = prop.FieldName; if (showArrayItems && prop.IsList) { fields[i] += "[*]"; } if (prop.FieldName == "_id" && isdbref) { isdbref = false; fields[i] = "$id"; } // if this property is DbRef, so if next property is _id, change to $id if (prop.IsDbRef) { isdbref = true; } } return(string.Join(".", fields)); }
/// <summary> /// Register a property as a DbRef - implement a custom Serialize/Deserialize actions to convert entity to $id, $ref only /// </summary> private static void RegisterDbRefItem(BsonMapper mapper, MemberMapper member, string collection) { // get entity var entity = mapper.GetEntityMapper(member.DataType); member.Serialize = (obj, m) => { // supports null values when "SerializeNullValues = true" if (obj == null) { return(BsonValue.Null); } var idField = entity.Id; // #768 if using DbRef with interface with no ID mapped if (idField == null) { throw new LiteException("There is no _id field mapped in your type: " + member.DataType.FullName); } var id = idField.Getter(obj); return(new BsonDocument { { "$id", m.Serialize(id.GetType(), id, 0) }, { "$ref", collection } }); }; member.Deserialize = (bson, m) => { var idRef = bson.AsDocument["$id"]; return(m.Deserialize(entity.ForType, idRef.IsNull ? bson : // if has no $id object was full loaded (via Include) - so deserialize using normal function new BsonDocument { { "_id", idRef } })); // if has $id, deserialize object using only _id object }; }
/// <summary> /// Register a property as a DbRefList - implement a custom Serialize/Deserialize actions to convert entity to $id, $ref only /// </summary> private static void RegisterDbRefList(BsonMapper mapper, MemberMapper member, string collection) { // get entity from list item type var entity = mapper.GetEntityMapper(member.UnderlyingType); member.Serialize = (list, m) => { // supports null values when "SerializeNullValues = true" if (list == null) { return(BsonValue.Null); } var result = new BsonArray(); var idField = entity.Id; foreach (var item in (IEnumerable)list) { if (item == null) { continue; } var id = idField.Getter(item); result.Add(new BsonDocument { { "$id", m.Serialize(id.GetType(), id, 0) }, { "$ref", collection } }); } return(result); }; member.Deserialize = (bson, m) => { var array = bson.AsArray; if (array.Count == 0) { return(m.Deserialize(member.DataType, array)); } // copy array changing $id to _id var result = new BsonArray(); foreach (var item in array) { var refId = item.AsDocument["$id"]; // if refId is null was included by "include" query, so "item" is full filled document if (refId.IsNull) { result.Add(item); } else { result.Add(new BsonDocument { { "_id", refId } }); } } return(m.Deserialize(member.DataType, result)); }; }
internal EntityBuilder(BsonMapper mapper) { _mapper = mapper; _entity = mapper.GetEntityMapper(typeof(T)); }