/// <summary> /// Create an index based in a custom getter value function. Take care if you already data in your collection (will not be work) /// </summary> public EntityBuilder <T> Index(string name, Func <T, BsonValue> getter, IndexOptions options) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (getter == null) { throw new ArgumentNullException("getter"); } if (options == null) { throw new ArgumentNullException("options"); } if (!BsonDocument.IsValidFieldName(name)) { throw new ArgumentException(string.Format("Field '{0}' has an invalid name.", name)); } // add a new property using a custom getter function var p = new PropertyMapper(); p.PropertyName = "__" + name; p.FieldName = name; p.Getter = new GenericGetter((obj) => getter((T)obj)); p.PropertyType = typeof(BsonValue); p.Setter = null; // readonly field p.IndexOptions = options; _prop[p.PropertyName] = p; return(this); }
/// <summary> /// Read all properties from a type - store in a static cache - exclude: Id and [BsonIgnore] /// </summary> public static Dictionary <string, PropertyMapper> GetProperties(Type type, Func <string, string> resolvePropertyName) { var dict = new Dictionary <string, PropertyMapper>(StringComparer.OrdinalIgnoreCase); var id = GetIdProperty(type); var ignore = typeof(BsonIgnoreAttribute); var idAttr = typeof(BsonIdAttribute); var fieldAttr = typeof(BsonFieldAttribute); var indexAttr = typeof(BsonIndexAttribute); #if PCL || NETSTANDARD var props = type.GetRuntimeProperties(); #else var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); #endif foreach (var prop in props) { // ignore indexer property if (prop.GetIndexParameters().Length > 0) { continue; } // ignore not read/write ////if (!prop.CanRead || !prop.CanWrite) continue; if (!prop.CanRead) { continue; } // [BsonIgnore] if (prop.IsDefined(ignore, false)) { continue; } // check if property has [BsonField] var bsonField = prop.IsDefined(fieldAttr, false); // create getter/setter IL function var getter = LitePlatform.Platform.ReflectionHandler.CreateGenericGetter(type, prop, bsonField); var setter = LitePlatform.Platform.ReflectionHandler.CreateGenericSetter(type, prop, bsonField); // if not getter or setter - no mapping if (getter == null) { continue; } if (dict.ContainsKey(prop.Name)) { // If the property is already in the dictionary, it's probably an override // Keep the first instance added continue; } var name = id != null && id.Equals(prop) ? "_id" : resolvePropertyName(prop.Name); // check if property has [BsonField] with a custom field name if (bsonField) { var field = (BsonFieldAttribute)prop.GetCustomAttributes(fieldAttr, false).FirstOrDefault(); if (field != null && field.Name != null) { name = field.Name; } } // check if property has [BsonId] to get with was setted AutoId = true var autoId = (BsonIdAttribute)prop.GetCustomAttributes(idAttr, false).FirstOrDefault(); // checks if this proerty has [BsonIndex] var index = (BsonIndexAttribute)prop.GetCustomAttributes(indexAttr, false).FirstOrDefault(); // if is _id field, do not accept index definition if (name == "_id") { index = null; } // 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(prop.Name, name); } // create a property mapper var p = new PropertyMapper { AutoId = autoId == null ? true : autoId.AutoId, FieldName = name, PropertyName = prop.Name, PropertyType = prop.PropertyType, IndexOptions = index == null ? null : index.Options, Getter = getter, Setter = setter }; dict.Add(prop.Name, p); } return(dict); }
/// <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); }
/// <summary> /// Read all properties from a type - store in a static cache - exclude: Id and [BsonIgnore] /// </summary> public static Dictionary <string, PropertyMapper> GetProperties(Type type, Func <string, string> resolvePropertyName) { var dict = new Dictionary <string, PropertyMapper>(); var id = GetIdProperty(type); var ignore = typeof(BsonIgnoreAttribute); var idAttr = typeof(BsonIdAttribute); var fieldAttr = typeof(BsonFieldAttribute); var indexAttr = typeof(BsonIndexAttribute); var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); var isInternal = type.Assembly.Equals(typeof(LiteDatabase).Assembly); foreach (var prop in props) { // ignore indexer property if (prop.GetIndexParameters().Length > 0) { continue; } // ignore not read/write if (!prop.CanRead || !prop.CanWrite) { continue; } // [BsonIgnore] if (prop.IsDefined(ignore, false)) { continue; } // create getter/setter IL function var getter = CreateGetMethod(type, prop); var setter = CreateSetMethod(type, prop); // if not getter or setter - no mapping if (getter == null) { continue; } var name = id != null && id.Equals(prop) ? "_id" : resolvePropertyName(prop.Name); // check if property has [BsonField] with a custom field name var field = (BsonFieldAttribute)prop.GetCustomAttributes(fieldAttr, false).FirstOrDefault(); if (field != null) { name = field.Name; } // check if property has [BsonId] to get with was setted AutoId = true var autoId = (BsonIdAttribute)prop.GetCustomAttributes(idAttr, false).FirstOrDefault(); // checks if this proerty has [BsonIndex] var index = (BsonIndexAttribute)prop.GetCustomAttributes(indexAttr, false).FirstOrDefault(); // if is _id field, do not accept index definition if (name == "_id") { index = null; } // test if field name is OK (avoid to check in all instances) - do not test internal classes, like DbRef if (BsonDocument.IsValidFieldName(name) == false && isInternal == false) { throw LiteException.InvalidFormat(prop.Name, name); } // create a property mapper var p = new PropertyMapper { AutoId = autoId == null ? true : autoId.AutoId, FieldName = name, PropertyName = prop.Name, PropertyType = prop.PropertyType, IndexOptions = index == null ? null : index.Options, Getter = getter, Setter = setter }; dict.Add(prop.Name, p); } return(dict); }
/// <summary> /// Read all properties from a type - store in a static cache - exclude: Id and [BsonIgnore] /// </summary> public static Dictionary <string, PropertyMapper> GetProperties(Type type, Func <string, string> resolvePropertyName) { var dict = new Dictionary <string, PropertyMapper>(StringComparer.OrdinalIgnoreCase); var id = GetIdProperty(type); var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); foreach (var prop in props) { // ignore indexer property if (prop.GetIndexParameters().Length > 0) { continue; } // ignore not read/write ////if (!prop.CanRead || !prop.CanWrite) continue; if (!prop.CanRead) { continue; } var mapper = (LiteMapperAttribute)prop.GetCustomAttributes(typeof(LiteMapperAttribute), false).FirstOrDefault() ?? new LiteMapperAttribute(); // [BsonIgnore] if (mapper.Ignore) { continue; } // check if property has [BsonField] var bsonField = prop.IsDefined(typeof(LiteMapperAttribute), false); // create getter/setter IL function var getter = CreateGetMethod(type, prop, bsonField); var setter = CreateSetMethod(type, prop, bsonField); // if not getter or setter - no mapping if (getter == null) { continue; } var name = id != null && id.Equals(prop) ? "_id" : resolvePropertyName(prop.Name); // check if property has [BsonField] with a custom field name if (!string.IsNullOrEmpty(mapper.FieldName)) { name = mapper.FieldName; } // 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(prop.Name, name); } // create a property mapper var p = new PropertyMapper { AutoId = mapper.AutoID != AutoID.False, FieldName = name, PropertyName = prop.Name, PropertyType = prop.PropertyType, IndexOptions = name == "_id" || !bsonField ? null : mapper.Indexes, Getter = getter, Setter = setter }; dict.Add(prop.Name, p); } return(dict); }