Mercurial > pub > bltoolkit
diff Source/Mapping/Fluent/FluentMap.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Mapping/Fluent/FluentMap.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,686 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +using BLToolkit.Data; +using BLToolkit.Data.DataProvider; +using BLToolkit.Reflection.Extension; + +namespace BLToolkit.Mapping.Fluent +{ + /// <summary> + /// FluentSettings + /// </summary> + /// <typeparam name="T"></typeparam> + public partial class FluentMap<T> + { + private readonly TypeExtension _typeExtension; + private List<IFluentMap> _childs; + private const string MemberNameSeparator = "."; + + /// <summary> + /// ctor + /// </summary> + public FluentMap() + : this(new TypeExtension { Name = typeof(T).FullName }, null) + { } + + /// <summary> + /// ctor + /// </summary> + /// <param name="typeExtension"></param> + /// <param name="childs"></param> + protected FluentMap(TypeExtension typeExtension, List<IFluentMap> childs) + { + this._typeExtension = typeExtension; + this._childs = childs; + + if (FluentConfig.MappingConfigurator.GetTableName != null) + { + this.TableName(null, null, FluentConfig.MappingConfigurator.GetTableName(typeof(T))); + } + } + + /// <summary> + /// TableNameAttribute + /// </summary> + /// <param name="name"></param> + /// <returns></returns> + public FluentMap<T> TableName(string name) + { + return this.TableName(null, null, name); + } + + /// <summary> + /// TableNameAttribute + /// </summary> + /// <param name="database"></param> + /// <param name="name"></param> + /// <returns></returns> + public FluentMap<T> TableName(string database, string name) + { + return this.TableName(database, null, name); + } + + /// <summary> + /// TableNameAttribute + /// </summary> + /// <param name="database"></param> + /// <param name="owner"></param> + /// <param name="name"></param> + /// <returns></returns> + public FluentMap<T> TableName(string database, string owner, string name) + { + ((IFluentMap)this).TableName(database, owner, name); + return this; + } + + /// <summary> + /// MapFieldAttribute + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <param name="prop"></param> + /// <param name="isInheritanceDiscriminator"></param> + /// <returns></returns> + public MapFieldMap<T,TR> MapField<TR>(Expression<Func<T, TR>> prop, bool isInheritanceDiscriminator) + { + return this.MapField(prop, null, null, isInheritanceDiscriminator); + } + + /// <summary> + /// MapFieldAttribute + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <param name="prop"></param> + /// <param name="mapName"></param> + /// <param name="storage"></param> + /// <param name="isInheritanceDiscriminator"></param> + /// <returns></returns> + public MapFieldMap<T, TR> MapField<TR>(Expression<Func<T, TR>> prop, string mapName = null, string storage = null, bool? isInheritanceDiscriminator = null) + { + string name = this.GetExprName(prop); + + if (mapName == null && FluentConfig.MappingConfigurator.GetColumnName != null) + { + mapName = FluentConfig.MappingConfigurator.GetColumnName(new MappedProperty { Name = name, Type = typeof(TR), ParentType = typeof(T) }); + } + + ((IFluentMap)this).MapField(name, mapName, storage, isInheritanceDiscriminator); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + private void MapFieldOnType(string origName, string mapName) + { + AttributeExtensionCollection attrs; + if (!this._typeExtension.Attributes.TryGetValue(Attributes.MapField.Name, out attrs)) + { + attrs = new AttributeExtensionCollection(); + this._typeExtension.Attributes.Add(Attributes.MapField.Name, attrs); + } + var attributeExtension = new AttributeExtension(); + attributeExtension.Values.Add(Attributes.MapField.OrigName, origName); + attributeExtension.Values.Add(Attributes.MapField.MapName, mapName); + attrs.Add(attributeExtension); + } + + private void MapFieldOnField(string origName, string mapName, string storage, bool? isInheritanceDiscriminator) + { + var member = this.GetMemberExtension(origName); + if (!string.IsNullOrEmpty(mapName)) + { + member.Attributes.Add(Attributes.MapField.Name, mapName); + } + if (null != storage) + { + member.Attributes.Add(Attributes.MapField.Storage, storage); + } + if (null != isInheritanceDiscriminator) + { + member.Attributes.Add(Attributes.MapField.IsInheritanceDiscriminator, this.ToString(isInheritanceDiscriminator.Value)); + } + } + + /// <summary> + /// PrimaryKeyAttribute + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <param name="prop"></param> + /// <param name="order"></param> + /// <returns></returns> + public MapFieldMap<T, TR> PrimaryKey<TR>(Expression<Func<T, TR>> prop, int order = -1) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).PrimaryKey(name, order); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// NonUpdatableAttribute + /// </summary> + /// <returns></returns> + public MapFieldMap<T, TR> NonUpdatable<TR>(Expression<Func<T, TR>> prop) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).NonUpdatable(name); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// IdentityAttribute + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <returns></returns> + public MapFieldMap<T, TR> Identity<TR>(Expression<Func<T, TR>> prop) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).Identity(name); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// SqlIgnoreAttribute + /// </summary> + /// <param name="prop"></param> + /// <param name="ignore"></param> + /// <returns></returns> + public MapFieldMap<T, TR> SqlIgnore<TR>(Expression<Func<T, TR>> prop, bool ignore = true) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).SqlIgnore(name, ignore); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// MapIgnoreAttribute + /// </summary> + /// <param name="prop"></param> + /// <param name="ignore"></param> + /// <returns></returns> + public MapFieldMap<T, TR> MapIgnore<TR>(Expression<Func<T, TR>> prop, bool ignore = true) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).MapIgnore(name, ignore); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// TrimmableAttribute + /// </summary> + /// <returns></returns> + public MapFieldMap<T, TR> Trimmable<TR>(Expression<Func<T, TR>> prop) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).Trimmable(name); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// MapValueAttribute + /// </summary> + /// <typeparam name="TV"> </typeparam> + /// <typeparam name="TR"> </typeparam> + /// <param name="prop"></param> + /// <param name="origValue"></param> + /// <param name="value"></param> + /// <param name="values"></param> + /// <returns></returns> + public MapFieldMap<T, TR> MapValue<TV, TR>(Expression<Func<T, TR>> prop, TR origValue, TV value, params TV[] values) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).MapValue(name, origValue, value, values); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// DefaultValueAttribute + /// </summary> + /// <param name="prop"> </param> + /// <param name="value"></param> + /// <returns></returns> + public MapFieldMap<T, TR> DefaultValue<TR>(Expression<Func<T, TR>> prop, TR value) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).DefaulValue(name, value); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// DbTypeAttribute + /// </summary> + /// <param name="prop"> </param> + /// <param name="dbType"></param> + /// <returns></returns> + public MapFieldMap<T,TR> DbType<TR>(Expression<Func<T, TR>> prop, DbType dbType) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).DbType<TR>(name, dbType); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// MemberMapperAttribute + /// </summary> + /// <param name="prop"> </param> + /// <param name="memberMapperType"></param> + /// <returns></returns> + public MapFieldMap<T,TR> MemberMapper<TR>(Expression<Func<T,TR>> prop, Type memberMapperType) + { + return this.MemberMapper(prop, null, memberMapperType); + } + + /// <summary> + /// MemberMapperAttribute + /// </summary> + /// <param name="prop"> </param> + /// <param name="memberType"></param> + /// <param name="memberMapperType"></param> + /// <returns></returns> + public MapFieldMap<T, TR> MemberMapper<TR>(Expression<Func<T, TR>> prop, Type memberType, Type memberMapperType) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).MemberMapper<TR>(name, memberType, memberMapperType); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// NullableAttribute + /// </summary> + /// <param name="prop"></param> + /// <param name="isNullable"></param> + /// <returns></returns> + public MapFieldMap<T, TR> Nullable<TR>(Expression<Func<T, TR>> prop, bool isNullable = true) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).Nullable(name, isNullable); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// LazyInstanceAttribute + /// </summary> + /// <param name="prop"></param> + /// <param name="isLazy"></param> + /// <returns></returns> + public MapFieldMap<T, TR> LazyInstance<TR>(Expression<Func<T, TR>> prop, bool isLazy = true) + { + string name = this.GetExprName(prop); + if (!GetIsVirtual(prop)) + throw new Exception("Property wich uses LazyInstance needs to be virtual!"); + ((IFluentMap)this).LazyInstance(name, isLazy); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// NullValueAttribute + /// </summary> + /// <param name="prop"></param> + /// <param name="value"></param> + /// <returns></returns> + public MapFieldMap<T, TR> NullValue<TR>(Expression<Func<T, TR>> prop, TR value) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).NullValue(name, value); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// AssociationAttribute + /// </summary> + /// <typeparam name="TRt"></typeparam> + /// <typeparam name="TR"> </typeparam> + /// <param name="prop"> </param> + /// <param name="canBeNull"></param> + /// <param name="thisKey"></param> + /// <param name="thisKeys"></param> + /// <returns></returns> + public MapFieldMap<T, TR>.AssociationMap<TRt> Association<TRt, TR>(Expression<Func<T, TR>> prop, bool canBeNull, Expression<Func<T, TRt>> thisKey, params Expression<Func<T, TRt>>[] thisKeys) + { + var keys = new List<Expression<Func<T, TRt>>>(thisKeys); + keys.Insert(0, thisKey); + return new MapFieldMap<T, TR>.AssociationMap<TRt>(new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop), canBeNull, keys); + } + + /// <summary> + /// AssociationAttribute + /// </summary> + /// <typeparam name="TRt"></typeparam> + /// <typeparam name="TR"> </typeparam> + /// <param name="prop"> </param> + /// <param name="thisKey"></param> + /// <param name="thisKeys"></param> + /// <returns></returns> + public MapFieldMap<T, TR>.AssociationMap<TRt> Association<TRt, TR>(Expression<Func<T, TR>> prop, Expression<Func<T, TRt>> thisKey, params Expression<Func<T, TRt>>[] thisKeys) + { + return this.Association(prop, true, thisKey, thisKeys); + } + + protected MapFieldMap<T, TR> Association<TRt, TR, TRf, TRo>(Expression<Func<T, TR>> prop, bool canBeNull + , IEnumerable<Expression<Func<T, TRt>>> thisKeys, IEnumerable<Expression<Func<TRf, TRo>>> otherKeys) + { + string name = this.GetExprName(prop); + ((IFluentMap)this).Association(name, canBeNull, this.KeysToString(thisKeys.ToArray()), this.KeysToString(otherKeys.ToArray())); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + /// <summary> + /// Reverse on BLToolkit.Mapping.Association.ParseKeys() + /// </summary> + /// <typeparam name="T1"></typeparam> + /// <typeparam name="T2"></typeparam> + /// <param name="keys"></param> + /// <returns></returns> + private string KeysToString<T1, T2>(IEnumerable<Expression<Func<T1, T2>>> keys) + { + return keys.Select(this.GetExprName).Aggregate((s1, s2) => s1 + ", " + s2); + } + + /// <summary> + /// RelationAttribute + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <param name="prop"></param> + /// <param name="slaveIndex"></param> + /// <param name="masterIndex"></param> + /// <returns></returns> + public MapFieldMap<T, TR> Relation<TR>(Expression<Func<T, TR>> prop, string slaveIndex = null, string masterIndex = null) + { + return this.Relation(prop, new[] { slaveIndex }, new[] { masterIndex }); + } + + /// <summary> + /// RelationAttribute + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <param name="prop"></param> + /// <param name="slaveIndex"></param> + /// <param name="masterIndex"></param> + /// <returns></returns> + public MapFieldMap<T, TR> Relation<TR>(Expression<Func<T, TR>> prop, string[] slaveIndex, string[] masterIndex) + { + string name = this.GetExprName(prop); + + slaveIndex = (slaveIndex ?? new string[0]).Where(i => !string.IsNullOrEmpty(i)).ToArray(); + masterIndex = (masterIndex ?? new string[0]).Where(i => !string.IsNullOrEmpty(i)).ToArray(); + + Type destinationType = typeof(TR); + + ((IFluentMap)this).Relation(name, destinationType, slaveIndex, masterIndex); + return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop); + } + + static void FillRelationIndex(string[] index, AttributeExtension attributeExtension, string indexName) + { + if (index.Any()) + { + var collection = new AttributeExtensionCollection(); + foreach (var s in index) + { + var ae = new AttributeExtension(); + ae.Values.Add(TypeExtension.AttrName.Name, s); + collection.Add(ae); + } + attributeExtension.Attributes.Add(indexName, collection); + } + } + + /// <summary> + /// MapValueAttribute + /// </summary> + /// <typeparam name="TV"></typeparam> + /// <param name="origValue"></param> + /// <param name="value"></param> + /// <param name="values"></param> + /// <returns></returns> + public FluentMap<T> MapValue<TV>(Enum origValue, TV value, params TV[] values) + { + ((IFluentMap)this).MapValue(origValue, value, values); + return this; + } + + /// <summary> + /// MapValueAttribute + /// </summary> + /// <typeparam name="TV"></typeparam> + /// <param name="origValue"></param> + /// <param name="value"></param> + /// <param name="values"></param> + /// <returns></returns> + public FluentMap<T> MapValue<TV>(object origValue, TV value, params TV[] values) + { + ((IFluentMap)this).MapValue(origValue, value, values); + return this; + } + + /// <summary> + /// MapFieldAttribute(isInheritanceDescriminator = true) + /// </summary> + /// <typeparam name="TR"></typeparam> + /// <param name="prop"></param> + /// <returns></returns> + public FluentMap<T> InheritanceField<TR>(Expression<Func<T, TR>> prop) + { + return this.MapField(prop, true); + } + + /// <summary> + /// InheritanceMappingAttribute + /// </summary> + /// <typeparam name="TC"></typeparam> + /// <param name="code"></param> + /// <returns></returns> + public FluentMap<T> InheritanceMapping<TC>(object code) + { + return this.InheritanceMapping<TC>(code, null); + } + + /// <summary> + /// InheritanceMappingAttribute + /// </summary> + /// <typeparam name="TC"></typeparam> + /// <param name="isDefault"></param> + /// <returns></returns> + public FluentMap<T> InheritanceMapping<TC>(bool isDefault) + { + return this.InheritanceMapping<TC>(null, isDefault); + } + + /// <summary> + /// InheritanceMappingAttribute + /// </summary> + /// <typeparam name="TC"></typeparam> + /// <param name="code"></param> + /// <param name="isDefault"></param> + /// <returns></returns> + public FluentMap<T> InheritanceMapping<TC>(object code, bool? isDefault) + { + ((IFluentMap)this).InheritanceMapping(typeof(TC), code, isDefault); + return this; + } + + protected void FillMapValueExtension<TR, TV>(AttributeNameCollection attributeCollection, TR origValue, TV value, TV[] values) + { + AttributeExtensionCollection list; + if (!attributeCollection.TryGetValue(Attributes.MapValue.Name, out list)) + { + list = new AttributeExtensionCollection(); + attributeCollection.Add(Attributes.MapValue.Name, list); + } + + var allValues = new List<TV>(values); + allValues.Insert(0, value); + var tvFullName = typeof(TV).FullName; + + foreach (var val in allValues) + { + var attributeExtension = new AttributeExtension(); + attributeExtension.Values.Add(Attributes.MapValue.OrigValue, origValue); + attributeExtension.Values.Add(TypeExtension.ValueName.Value, Convert.ToString(val)); + attributeExtension.Values.Add(TypeExtension.ValueName.Value + TypeExtension.ValueName.TypePostfix, tvFullName); + list.Add(attributeExtension); + } + } + + protected void FillMemberMapperExtension(AttributeNameCollection attributeCollection, Type memberType, Type memberMapperType) + { + AttributeExtensionCollection attrs; + if (!attributeCollection.TryGetValue(Attributes.MemberMapper.Name, out attrs)) + { + attrs = new AttributeExtensionCollection(); + attributeCollection.Add(Attributes.MemberMapper.Name, attrs); + } + var attributeExtension = new AttributeExtension(); + attributeExtension.Values.Add(Attributes.MemberMapper.MemberType, memberType); + attributeExtension.Values.Add(Attributes.MemberMapper.MemberMapperType, memberMapperType); + attrs.Add(attributeExtension); + } + + /// <summary> + /// Fluent settings result + /// </summary> + /// <returns></returns> + public ExtensionList Map() + { + var result = new ExtensionList(); + this.MapTo(result); + return result; + } + + /// <summary> + /// Apply fluent settings to DbManager + /// </summary> + /// <param name="dbManager"></param> + public void MapTo(DbManager dbManager) + { + var ms = dbManager.MappingSchema ?? (dbManager.MappingSchema = Mapping.Map.DefaultSchema); + this.MapTo(ms); + } + + /// <summary> + /// Apply fluent settings to DataProviderBase + /// </summary> + /// <param name="dataProvider"></param> + public void MapTo(DataProviderBase dataProvider) + { + var ms = dataProvider.MappingSchema ?? (dataProvider.MappingSchema = Mapping.Map.DefaultSchema); + this.MapTo(ms); + } + + /// <summary> + /// Apply fluent settings to MappingSchema + /// </summary> + /// <param name="mappingSchema"></param> + public void MapTo(MappingSchema mappingSchema) + { + var extensions = mappingSchema.Extensions ?? (mappingSchema.Extensions = new ExtensionList()); + this.MapTo(extensions); + } + + /// <summary> + /// Apply fluent settings to ExtensionList + /// </summary> + /// <param name="extensions"></param> + public void MapTo(ExtensionList extensions) + { + var ext = this._typeExtension; + TypeExtension oldExt; + if (extensions.TryGetValue(ext.Name, out oldExt)) + { + FluentMapHelper.MergeExtensions(ext, ref oldExt); + } + else + { + extensions.Add(ext); + } + this.EachChilds(m => m.MapTo(extensions)); + } + + protected MemberExtension GetMemberExtension<TR>(Expression<Func<T, TR>> prop) + { + string name = this.GetExprName(prop); + return this.GetMemberExtension(name); + } + + protected MemberExtension GetMemberExtension(string name) + { + MemberExtension member; + if (!this._typeExtension.Members.TryGetValue(name, out member)) + { + member = new MemberExtension { Name = name }; + this._typeExtension.Members.Add(member); + } + return member; + } + + private string GetExprName<TT, TR>(Expression<Func<TT, TR>> prop) + { + string result = null; + var memberExpression = prop.Body as MemberExpression; + while (null != memberExpression) + { + result = null == result ? "" : MemberNameSeparator + result; + result = memberExpression.Member.Name + result; + memberExpression = memberExpression.Expression as MemberExpression; + } + if (null == result) + { + throw new ArgumentException("Fail member access expression."); + } + return result; + } + + static bool GetIsVirtual<TT, TR>(Expression<Func<TT, TR>> prop) + { + var memberExpression = prop.Body as MemberExpression; + if (memberExpression != null) + { + var prpInfo = memberExpression.Member as PropertyInfo; + if (prpInfo != null && !prpInfo.GetGetMethod().IsVirtual) + { + return false; + } + } + + return true; + } + + /// <summary> + /// Invert for BLToolkit.Reflection.Extension.TypeExtension.ToBoolean() + /// </summary> + /// <param name="value"></param> + /// <returns></returns> + protected string ToString(bool value) + { + return Convert.ToString(value); + } + + private void EachChilds(Action<IFluentMap> action) + { + foreach (var childMap in this.Childs) + { + action(childMap); + } + } + + private List<IFluentMap> Childs + { + get + { + if (null == this._childs) + { + this._childs = new List<IFluentMap>(); + var thisType = typeof(T); + var fmType = typeof(FluentMap<>); + // Find child only first generation ... other generation find recursive + foreach (var childType in thisType.Assembly.GetTypes().Where(t => t.BaseType == thisType)) + { + this._childs.Add((IFluentMap)Activator.CreateInstance(fmType.MakeGenericType(childType))); + } + } + return this._childs; + } + } + } +}