Esempio n. 1
0
        internal LiteCollection(string name, BsonAutoId autoId, ILiteEngine engine, BsonMapper mapper)
        {
            _collection = name ?? mapper.ResolveCollectionName(typeof(T));
            _engine     = engine;
            _mapper     = mapper;
            _includes   = new List <BsonExpression>();

            // if strong typed collection, get _id member mapped (if exists)
            if (typeof(T) == typeof(BsonDocument))
            {
                _entity = null;
                _id     = null;
                _autoId = autoId;
            }
            else
            {
                _entity = mapper.GetEntityMapper(typeof(T));
                _id     = _entity.Id;

                if (_id != null && _id.AutoId)
                {
                    _autoId =
                        _id.DataType == typeof(Int32) || _id.DataType == typeof(Int32?) ? BsonAutoId.Int32 :
                        _id.DataType == typeof(Int64) || _id.DataType == typeof(Int64?) ? BsonAutoId.Int64 :
                        _id.DataType == typeof(Guid) || _id.DataType == typeof(Guid?) ? BsonAutoId.Guid :
                        BsonAutoId.ObjectId;
                }
                else
                {
                    _autoId = BsonAutoId.ObjectId;
                }
            }
        }
        /// <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) =>
            {
                var idField = entity.Id;

                var id = idField.Getter(obj);

                return(new BsonDocument
                {
                    { "$id", new BsonValue(id) },
                    { "$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
            };
        }
        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;
                }
            }
        }
        /// <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) =>
            {
                var result  = new BsonArray();
                var idField = entity.Id;

                foreach (var item in (IEnumerable)list)
                {
                    if (item == null)
                    {
                        continue;
                    }

                    result.Add(new BsonDocument
                    {
                        { "$id", new BsonValue(idField.Getter(item)) },
                        { "$ref", collection }
                    });
                }

                return(result);
            };

            member.Deserialize = (bson, m) =>
            {
                var array = bson.AsArray;

                if (array.Count == 0)
                {
                    return(m.Deserialize(member.DataType, array));
                }

                var hasIdRef = array[0].AsDocument == null || array[0].AsDocument["$id"].IsNull;

                if (hasIdRef)
                {
                    // if no $id, deserialize as full (was loaded via Include)
                    return(m.Deserialize(member.DataType, array));
                }
                else
                {
                    // copy array changing $id to _id
                    var arr = new BsonArray();

                    foreach (var item in array)
                    {
                        arr.Add(new BsonDocument {
                            { "_id", item.AsDocument["$id"] }
                        });
                    }

                    return(m.Deserialize(member.DataType, arr));
                }
            };
        }
Esempio n. 5
0
        /// <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, ITypeNameBinder typeNameBinder, 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(0, "There is no _id field mapped in your type: " + member.DataType.FullName);
                }

                var id = idField.Getter(obj);

                var bsonDocument = new BsonDocument
                {
                    ["$id"]  = m.Serialize(id.GetType(), id, 0),
                    ["$ref"] = collection
                };

                if (member.DataType != obj.GetType())
                {
                    bsonDocument["$type"] = typeNameBinder.GetName(obj.GetType());
                }

                return(bsonDocument);
            };

            member.Deserialize = (bson, m) =>
            {
                var idRef   = bson.IsDocument ? bson["$id"] : BsonValue.Null;
                var missing = bson.IsDocument ? (bson["$missing"] == true) : false;

                if (missing)
                {
                    return(null);
                }

                return(m.Deserialize(entity.ForType,
                                     idRef.IsNull ?
                                     bson : // if has no $id object was full loaded (via Include) - so deserialize using normal function
                                     bson.AsDocument.ContainsKey("$type") ?
                                     new BsonDocument {
                    ["_id"] = idRef, ["_type"] = bson["$type"]
                } :
                                     new BsonDocument {
                    ["_id"] = idRef
                }));                                           // if has $id, deserialize object using only _id object
            };
        }
Esempio n. 6
0
        /// <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);

                var bsonDocument = new BsonDocument
                {
                    { "$id", m.Serialize(id.GetType(), id, 0) },
                    { "$ref", collection }
                };

                if (member.DataType.GetTypeInfo().IsInterface || member.DataType.GetTypeInfo().IsAbstract)
                {
                    bsonDocument["$type"] = obj.GetType().FullName + ", " +
                                            obj.GetType().GetTypeInfo().Assembly.GetName().Name;
                }

                return(bsonDocument);
            };

            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
                                     member.DataType.GetTypeInfo().IsAbstract || member.DataType.GetTypeInfo().IsInterface
                            ? new BsonDocument {
                    { "_id", idRef }, { "_type", bson.AsDocument["$type"] }
                }
                            : new BsonDocument {
                    { "_id", idRef }
                }));                                              // if has $id, deserialize object using only _id object
            };
        }
Esempio n. 7
0
        /// <summary>
        /// Returns document field name for some type member
        /// </summary>
        private string ResolveMember(MemberInfo member)
        {
            var name = member.Name;

            // get class entity from mapper
            var entity = _mapper.GetEntityMapper(member.DeclaringType);

            var field = entity.Members.FirstOrDefault(x => x.MemberName == name);

            if (field == null)
            {
                throw new NotSupportedException($"Member {name} not found on BsonMapper for type {member.DeclaringType}.");
            }

            return("." + field.FieldName);
        }
        /// <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));
        }
Esempio n. 9
0
        /// <summary>
        /// Based on an 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") (prefix = "Customers."
        /// </summary>
        public string GetField(Expression expr, string prefix = "")
        {
            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 LiteException.PropertyNotMapped(property);
                }

                // if property is a IEnumerable, gets underlayer type (otherwise, gets PropertyType)
                type = prop.UnderlyingType;

                fields[i] = prop.FieldName;

                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));
        }
Esempio n. 10
0
        /// <summary>
        /// Returns document field name for some type member
        /// </summary>
        private string ResolveMember(MemberInfo member)
        {
            var name = member.Name;

            // checks if parent field are not DbRef (checks for same dataType)
            var isParentDbRef = _dbRefType != null && _dbRefType == member.DeclaringType;

            // get class entity from mapper
            var entity = _mapper.GetEntityMapper(member.DeclaringType);

            // get mapped field from entity
            var field = entity.Members.FirstOrDefault(x => x.MemberName == name);

            if (field == null)
            {
                throw new NotSupportedException($"Member {name} not found on BsonMapper for type {member.DeclaringType}.");
            }

            // define if this field are DbRef (child will need check parent)
            _dbRefType = field.IsDbRef ? field.UnderlyingType : null;

            // if parent call is DbRef and are calling _id field, rename to $id
            return("." + (isParentDbRef && field.FieldName == "_id" ? "$id" : field.FieldName));
        }
Esempio n. 11
0
        /// <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) =>
            {
                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", new BsonValue(id) },
                    { "$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
            };
        }
Esempio n. 12
0
 internal EntityBuilder(BsonMapper mapper, ITypeNameBinder typeNameBinder)
 {
     _mapper         = mapper;
     _typeNameBinder = typeNameBinder;
     _entity         = mapper.GetEntityMapper(typeof(T));
 }
Esempio n. 13
0
        /// <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));
            };
        }
Esempio n. 14
0
 internal EntityBuilder(BsonMapper mapper)
 {
     _mapper = mapper;
     _entity = mapper.GetEntityMapper(typeof(T));
 }
Esempio n. 15
0
        /// <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, ITypeNameBinder typeNameBinder, 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);

                    var bsonDocument = new BsonDocument
                    {
                        ["$id"]  = m.Serialize(id.GetType(), id, 0),
                        ["$ref"] = collection
                    };

                    if (member.UnderlyingType != item.GetType())
                    {
                        bsonDocument["$type"] = typeNameBinder.GetName(item.GetType());
                    }

                    result.Add(bsonDocument);
                }

                return(result);
            };

            member.Deserialize = (bson, m) =>
            {
                if (bson.IsArray == false)
                {
                    return(null);
                }

                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)
                {
                    if (item.IsDocument == false)
                    {
                        continue;
                    }

                    var doc      = item.AsDocument;
                    var idRef    = doc["$id"];
                    var missing  = doc["$missing"] == true;
                    var included = doc.ContainsKey("$ref") == false;

                    // if referece document are missing, do not inlcude on output list
                    if (missing)
                    {
                        continue;
                    }

                    // if refId is null was included by "include" query, so "item" is full filled document
                    if (included)
                    {
                        item["_id"] = idRef;
                        if (item.AsDocument.ContainsKey("$type"))
                        {
                            item["_type"] = item["$type"];
                        }

                        result.Add(item);
                    }
                    else
                    {
                        var bsonDocument = new BsonDocument {
                            ["_id"] = idRef
                        };

                        if (item.AsDocument.ContainsKey("$type"))
                        {
                            bsonDocument["_type"] = item["$type"];
                        }

                        result.Add(bsonDocument);
                    }
                }

                return(m.Deserialize(member.DataType, result));
            };
        }
Esempio n. 16
0
        /// <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, ITypeNameBinder typeNameBinder, 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(0, "There is no _id field mapped in your type: " + member.DataType.FullName);
                }

                var id = idField.Getter(obj);

                var bsonDocument = new BsonDocument
                {
                    ["$id"]  = m.Serialize(id.GetType(), id, 0),
                    ["$ref"] = collection
                };

                if (member.DataType != obj.GetType())
                {
                    bsonDocument["$type"] = typeNameBinder.GetName(obj.GetType());
                }

                return(bsonDocument);
            };

            member.Deserialize = (bson, m) =>
            {
                // if not a document (maybe BsonValue.null) returns null
                if (bson == null || bson.IsDocument == false)
                {
                    return(null);
                }

                var doc      = bson.AsDocument;
                var idRef    = doc["$id"];
                var missing  = doc["$missing"] == true;
                var included = doc.ContainsKey("$ref") == false;

                if (missing)
                {
                    return(null);
                }

                if (included)
                {
                    doc["_id"] = idRef;
                    if (doc.ContainsKey("$type"))
                    {
                        doc["_type"] = bson["$type"];
                    }

                    return(m.Deserialize(entity.ForType, doc));
                }
                else
                {
                    return(m.Deserialize(entity.ForType,
                                         doc.ContainsKey("$type") ?
                                         new BsonDocument {
                        ["_id"] = idRef, ["_type"] = bson["$type"]
                    } :
                                         new BsonDocument {
                        ["_id"] = idRef
                    }));                                           // if has $id, deserialize object using only _id object
                }
            };
        }