예제 #1
0
 internal EntityBuilder(BsonMapper mapper, ITypeNameBinder typeNameBinder)
 {
     _mapper         = mapper;
     _typeNameBinder = typeNameBinder;
     _entity         = mapper.GetEntityMapper(typeof(T));
 }
예제 #2
0
        /// <summary>
        /// Use this method to override how your class can be, by default, mapped from entity to Bson document.
        /// Returns an EntityMapper from each requested Type
        /// </summary>
        protected virtual EntityMapper BuildEntityMapper(Type type)
        {
            var mapper = new EntityMapper
            {
                Members = new List <MemberMapper>(),
                ForType = type
            };

            var idAttr     = typeof(BsonIdAttribute);
            var ignoreAttr = typeof(BsonIgnoreAttribute);
            var fieldAttr  = typeof(BsonFieldAttribute);
            var indexAttr  = typeof(BsonIndexAttribute);
            var dbrefAttr  = typeof(BsonRefAttribute);

            var members = this.GetTypeMembers(type);
            var id      = this.GetIdMember(members);

            foreach (var memberInfo in members)
            {
                // checks [BsonIgnore]
                if (memberInfo.IsDefined(ignoreAttr, true))
                {
                    continue;
                }

                // checks field name conversion
                var name = this.ResolveFieldName(memberInfo.Name);

                // check if property has [BsonField]
                var field = (BsonFieldAttribute)memberInfo.GetCustomAttributes(fieldAttr, false).FirstOrDefault();

                // check if property has [BsonField] with a custom field name
                if (field != null && field.Name != null)
                {
                    name = field.Name;
                }

                // checks if memberInfo is id field
                if (memberInfo == id)
                {
                    name = "_id";
                }

                // test if field name is OK (avoid to check in all instances) - do not test internal classes, like DbRef
                if (BsonDocument.IsValidFieldName(name) == false)
                {
                    throw LiteException.InvalidFormat(memberInfo.Name);
                }

                // create getter/setter function
                var getter = Reflection.CreateGenericGetter(type, memberInfo);
                var setter = Reflection.CreateGenericSetter(type, memberInfo);

                // check if property has [BsonId] to get with was setted AutoId = true
                var autoId = (BsonIdAttribute)memberInfo.GetCustomAttributes(idAttr, false).FirstOrDefault();

                // get data type
                var dataType = memberInfo is PropertyInfo ?
                               (memberInfo as PropertyInfo).PropertyType :
                               (memberInfo as FieldInfo).FieldType;

                // check if datatype is list/array
                var isList = Reflection.IsList(dataType);

                // create a property mapper
                var member = new MemberMapper
                {
                    AutoId         = autoId == null ? true : autoId.AutoId,
                    FieldName      = name,
                    MemberName     = memberInfo.Name,
                    DataType       = dataType,
                    IsList         = isList,
                    UnderlyingType = isList ? Reflection.GetListItemType(dataType) : dataType,
                    Getter         = getter,
                    Setter         = setter
                };

                // check if property has [BsonRef]
                var dbRef = (BsonRefAttribute)memberInfo.GetCustomAttributes(dbrefAttr, false).FirstOrDefault();

                if (dbRef != null && memberInfo is PropertyInfo)
                {
                    BsonMapper.RegisterDbRef(this, member, dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType));
                }

                // support callback to user modify member mapper
                if (this.ResolveMember != null)
                {
                    this.ResolveMember(type, memberInfo, member);
                }

                // test if has name and there is no duplicate field
                if (member.FieldName != null && mapper.Members.Any(x => x.FieldName == name) == false)
                {
                    mapper.Members.Add(member);
                }
            }

            return(mapper);
        }
예제 #3
0
        /// <summary>
        /// Get best construtor to use to initialize this entity.
        /// - Look if contains [BsonCtor] attribute
        /// - Look for parameterless ctor
        /// - Look for first contructor with parameter and use BsonDocument to send RawValue
        /// </summary>
        protected virtual CreateObject GetTypeCtor(EntityMapper mapper)
        {
            var ctors = mapper.ForType.GetConstructors();

            var ctor =
                ctors.FirstOrDefault(x => x.GetCustomAttribute <BsonCtorAttribute>() != null && x.GetParameters().All(p => Reflection.ConvertType.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType) || p.ParameterType.GetTypeInfo().IsEnum)) ??
                ctors.FirstOrDefault(x => x.GetParameters().Length == 0) ??
                ctors.FirstOrDefault(x => x.GetParameters().All(p => Reflection.ConvertType.ContainsKey(p.ParameterType) || _customDeserializer.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType) || p.ParameterType.GetTypeInfo().IsEnum));

            if (ctor == null)
            {
                return(null);
            }

            var pars = new List <Expression>();
            var pDoc = Expression.Parameter(typeof(BsonDocument), "_doc");

            // otherwise, need access ctor with parameter
            foreach (var p in ctor.GetParameters())
            {
                // try first get converted named (useful for Id => _id)
                var name = mapper.Members.FirstOrDefault(x => x.MemberName.Equals(p.Name, StringComparison.OrdinalIgnoreCase))?.FieldName ??
                           p.Name;

                var expr = Expression.MakeIndex(pDoc,
                                                Reflection.DocumentItemProperty,
                                                new[] { Expression.Constant(name) });

                if (_customDeserializer.TryGetValue(p.ParameterType, out var func))
                {
                    var deserializer = Expression.Constant(func);
                    var call         = Expression.Invoke(deserializer, expr);
                    var cast         = Expression.Convert(call, p.ParameterType);
                    pars.Add(cast);
                }
                else if (_basicTypes.Contains(p.ParameterType))
                {
                    var typeExpr        = Expression.Constant(p.ParameterType);
                    var rawValue        = Expression.Property(expr, typeof(BsonValue).GetProperty("RawValue"));
                    var convertTypeFunc = Expression.Call(typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) }), rawValue, typeExpr);
                    var cast            = Expression.Convert(convertTypeFunc, p.ParameterType);
                    pars.Add(cast);
                }
                else if (p.ParameterType.GetTypeInfo().IsEnum&& this.EnumAsInteger)
                {
                    var typeExpr        = Expression.Constant(p.ParameterType);
                    var rawValue        = Expression.PropertyOrField(expr, "AsInt32");
                    var convertTypeFunc = Expression.Call(typeof(Enum).GetMethod("ToObject", new Type[] { typeof(Type), typeof(Int32) }), typeExpr, rawValue);
                    var cast            = Expression.Convert(convertTypeFunc, p.ParameterType);
                    pars.Add(cast);
                }
                else if (p.ParameterType.GetTypeInfo().IsEnum)
                {
                    var typeExpr        = Expression.Constant(p.ParameterType);
                    var rawValue        = Expression.PropertyOrField(expr, "AsString");
                    var convertTypeFunc = Expression.Call(typeof(Enum).GetMethod("Parse", new Type[] { typeof(Type), typeof(string) }), typeExpr, rawValue);
                    var cast            = Expression.Convert(convertTypeFunc, p.ParameterType);
                    pars.Add(cast);
                }
                else
                {
                    var propInfo = Reflection.ConvertType[p.ParameterType];
                    var prop     = Expression.Property(expr, propInfo);
                    pars.Add(prop);
                }
            }

            // get `new MyClass([params])` expression
            var newExpr = Expression.New(ctor, pars.ToArray());

            // get lambda expression
            var fn = mapper.ForType.GetTypeInfo().IsClass ?
                     Expression.Lambda <CreateObject>(newExpr, pDoc).Compile() :                                    // Class
                     Expression.Lambda <CreateObject>(Expression.Convert(newExpr, typeof(object)), pDoc).Compile(); // Struct

            return(fn);
        }
예제 #4
0
 internal EntityBuilder(BsonMapper mapper)
 {
     _mapper = mapper;
     _entity = mapper.GetEntityMapper(typeof(T));
 }
예제 #5
0
        /// <summary>
        /// Use this method to override how your class can be, by default, mapped from entity to Bson document.
        /// Returns an EntityMapper from each requested Type
        /// </summary>
        protected virtual EntityMapper BuildEntityMapper(Type type)
        {
            var mapper = new EntityMapper(type);

            var idAttr     = typeof(BsonIdAttribute);
            var ignoreAttr = typeof(BsonIgnoreAttribute);
            var fieldAttr  = typeof(BsonFieldAttribute);
            var dbrefAttr  = typeof(BsonRefAttribute);

            var members = this.GetTypeMembers(type);
            var id      = this.GetIdMember(members);

            foreach (var memberInfo in members)
            {
                // checks [BsonIgnore]
                if (CustomAttributeExtensions.IsDefined(memberInfo, ignoreAttr, true))
                {
                    continue;
                }

                // checks field name conversion
                var name = this.ResolveFieldName(memberInfo.Name);

                // check if property has [BsonField]
                var field = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, fieldAttr, true).FirstOrDefault();

                // check if property has [BsonField] with a custom field name
                if (field != null && field.Name != null)
                {
                    name = field.Name;
                }

                // checks if memberInfo is id field
                if (memberInfo == id)
                {
                    name = "_id";
                }

                // create getter/setter function
                var getter = Reflection.CreateGenericGetter(type, memberInfo);
                var setter = Reflection.CreateGenericSetter(type, memberInfo);

                // check if property has [BsonId] to get with was setted AutoId = true
                var autoId = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, idAttr, true).FirstOrDefault();

                // get data type
                var dataType = memberInfo is PropertyInfo ?
                               (memberInfo as PropertyInfo).PropertyType :
                               (memberInfo as FieldInfo).FieldType;

                // check if datatype is list/array
                var isEnumerable = Reflection.IsEnumerable(dataType);

                // create a property mapper
                var member = new MemberMapper
                {
                    AutoId         = autoId == null ? true : autoId.AutoId,
                    FieldName      = name,
                    MemberName     = memberInfo.Name,
                    DataType       = dataType,
                    IsEnumerable   = isEnumerable,
                    UnderlyingType = isEnumerable ? Reflection.GetListItemType(dataType) : dataType,
                    Getter         = getter,
                    Setter         = setter
                };

                // check if property has [BsonRef]
                var dbRef = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, dbrefAttr, false).FirstOrDefault();

                if (dbRef != null && memberInfo is PropertyInfo)
                {
                    BsonMapper.RegisterDbRef(this, member, _typeNameBinder, dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType));
                }

                // support callback to user modify member mapper
                this.ResolveMember?.Invoke(type, memberInfo, member);

                // test if has name and there is no duplicate field
                if (member.FieldName != null && mapper.Members.Any(x => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) == false)
                {
                    mapper.Members.Add(member);
                }
            }

            return(mapper);
        }