Mercurial > pub > bltoolkit
diff Source/Reflection/MetadataProvider/ExtensionMetadataProvider.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/Reflection/MetadataProvider/ExtensionMetadataProvider.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,659 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; + +using BLToolkit.Common; +using BLToolkit.DataAccess; + +using Convert=System.Convert; + +namespace BLToolkit.Reflection.MetadataProvider +{ + using Extension; + using Mapping; + + public class ExtensionMetadataProvider : MetadataProviderBase + { + #region Helpers + + private static object GetValue(TypeExtension typeExtension, MemberAccessor member, string elemName, out bool isSet) + { + AttributeExtensionCollection ext; + isSet = typeExtension[member.Name].Attributes.TryGetValue(elemName, out ext); + return isSet ? ext.Value : null; + } + + #endregion + + #region GetFieldName + + public override string GetFieldName(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var value = GetValue(typeExtension, member, "MapField", out isSet); + + if (value != null) + return value.ToString(); + + return base.GetFieldName(typeExtension, member, out isSet); + } + + #endregion + + #region GetFieldStorage + + public override string GetFieldStorage(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var value = GetValue(typeExtension, member, "FieldStorage", out isSet); + + if (value != null) + return value.ToString(); + + return base.GetFieldStorage(typeExtension, member, out isSet); + } + + #endregion + + #region GetInheritanceDiscriminator + + public override bool GetInheritanceDiscriminator(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var value = GetValue(typeExtension, member, "IsInheritanceDiscriminator", out isSet); + + if (value != null) + return TypeExtension.ToBoolean(value); + + return base.GetInheritanceDiscriminator(typeExtension, member, out isSet); + } + + #endregion + + #region GetMapIgnore + + public override bool GetMapIgnore(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var value = GetValue(typeExtension, member, "MapIgnore", out isSet); + + if (value != null) + return TypeExtension.ToBoolean(value); + + return base.GetMapIgnore(typeExtension, member, out isSet) || GetAssociation(typeExtension, member) != null; + } + + #endregion + + #region GetMapField + + public override MapFieldAttribute GetMapField(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var extList = typeExtension[member.Name]["MapField"]; + + if (extList != AttributeExtensionCollection.Null) + { + isSet = true; + var attr = new MapFieldAttribute(); + + var extFormat = extList.FirstOrDefault(x => x.Name == "Format"); + var extMapName = extList.FirstOrDefault(x => x.Name == "MapName"); + var extIsInheritanceDiscriminator = extList.FirstOrDefault(x => x.Name == "IsInheritanceDiscriminator"); + var extOrigName = extList.FirstOrDefault(x => x.Name == "OrigName"); + var extStorage = extList.FirstOrDefault(x => x.Name == "Storage"); + + if (extFormat != null) + attr.Format = (string)extFormat.Value; + if (extMapName != null) + attr.MapName = (string)extMapName.Value; + if (extFormat != null) + attr.IsInheritanceDiscriminator = Convert.ToBoolean(extIsInheritanceDiscriminator.Value); + if (extFormat != null) + attr.OrigName = (string)extOrigName.Value; + if (extFormat != null) + attr.Storage = (string)extStorage.Value; + return attr; + } + + return base.GetMapField(typeExtension, member, out isSet); + } + + #endregion + + #region GetDbType + + [CLSCompliant(false)] + public override DbTypeAttribute GetDbType(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var extList = typeExtension[member.Name]["DbType"]; + + if (extList != AttributeExtensionCollection.Null) + { + isSet = true; + var attr = new DbTypeAttribute(DbType.String); + + var extDbType = extList.FirstOrDefault(x => x.Name == "DbType"); + var extSize = extList.FirstOrDefault(x => x.Name == "Size"); + + DbType dbType; + if (extDbType != null) + { +#if SILVERLIGHT || FW4 + DbType.TryParse(extDbType.Value.ToString(), out dbType); +#else + dbType = (DbType)Enum.Parse(typeof(DbType), extDbType.Value.ToString()); +#endif + attr.DbType = dbType; + } + if (extSize != null) + { + attr.Size = int.Parse(extSize.Value.ToString()); + } + return attr; + } + + return base.GetDbType(typeExtension, member, out isSet); + } + + #endregion + + #region GetPrimaryKey + + public override PrimaryKeyAttribute GetPrimaryKey(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var extList = typeExtension[member.Name]["PrimaryKey"]; + + if (extList != AttributeExtensionCollection.Null) + { + isSet = true; + int order = -1; + var extOrder = extList.FirstOrDefault(x => x.Name == "Order"); + if (extOrder != null) + { + order = int.Parse(extOrder.Value.ToString()); + } + var attr = new PrimaryKeyAttribute(order); + return attr; + } + + return base.GetPrimaryKey(typeExtension, member, out isSet); + } + + #endregion + + + #region GetTrimmable + + public override bool GetTrimmable(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + if (member.Type == typeof(string)) + { + var value = GetValue(typeExtension, member, "Trimmable", out isSet); + + if (value != null) + return TypeExtension.ToBoolean(value); + } + + return base.GetTrimmable(typeExtension, member, out isSet); + } + + #endregion + + #region GetMapValues + + public override MapValue[] GetMapValues(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var extList = typeExtension[member.Name]["MapValue"]; + + if (extList == AttributeExtensionCollection.Null) + return GetMapValues(typeExtension, member.Type, out isSet); + + var list = new List<MapValue>(extList.Count); + + foreach (var ext in extList) + { + var origValue = ext["OrigValue"]; + + if (origValue != null) + { + origValue = TypeExtension.ChangeType(origValue, member.Type); + list.Add(new MapValue(origValue, ext.Value)); + } + } + + isSet = true; + + return list.ToArray(); + } + + const FieldAttributes EnumField = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal; + + static List<MapValue> GetEnumMapValues(TypeExtension typeExt, Type type) + { + List<MapValue> mapValues = null; + + var fields = type.GetFields(); + + foreach (var fi in fields) + { + if ((fi.Attributes & EnumField) == EnumField) + { + var attrExt = typeExt[fi.Name]["MapValue"]; + + if (attrExt.Count == 0) + continue; + + var list = new List<object>(attrExt.Count); + var origValue = Enum.Parse(type, fi.Name, false); + + list.AddRange(from ae in attrExt where ae.Value != null select ae.Value); + + if (list.Count > 0) + { + if (mapValues == null) + mapValues = new List<MapValue>(fields.Length); + + mapValues.Add(new MapValue(origValue, list.ToArray())); + } + } + } + + return mapValues; + } + + static List<MapValue> GetTypeMapValues(TypeExtension typeExt, Type type) + { + var extList = typeExt.Attributes["MapValue"]; + + if (extList == AttributeExtensionCollection.Null) + return null; + + var attrs = new List<MapValue>(extList.Count); + + foreach (var ext in extList) + { + var origValue = ext["OrigValue"]; + + if (origValue != null) + { + origValue = TypeExtension.ChangeType(origValue, type); + attrs.Add(new MapValue(origValue, ext.Value)); + } + } + + return attrs; + } + + public override MapValue[] GetMapValues(TypeExtension typeExt, Type type, out bool isSet) + { + List<MapValue> list = null; + + if (TypeHelper.IsNullable(type)) + type = type.GetGenericArguments()[0]; + + if (type.IsEnum) + list = GetEnumMapValues(typeExt, type); + + if (list == null) + list = GetTypeMapValues(typeExt, type); + + isSet = list != null; + + return isSet? list.ToArray(): null; + } + + #endregion + + #region GetDefaultValue + + public override object GetDefaultValue(MappingSchema mappingSchema, TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var value = typeExtension[member.Name]["DefaultValue"].Value; + + if (value != null) + { + isSet = true; + return TypeExtension.ChangeType(value, member.Type); + } + + return GetDefaultValue(mappingSchema, typeExtension, member.Type, out isSet); + } + + public override object GetDefaultValue(MappingSchema mappingSchema, TypeExtension typeExt, Type type, out bool isSet) + { + object value = null; + + if (type.IsEnum) + value = GetEnumDefaultValueFromExtension(typeExt, type); + + if (value == null) + value = typeExt.Attributes["DefaultValue"].Value; + + isSet = value != null; + + return TypeExtension.ChangeType(value, type); + } + + private static object GetEnumDefaultValueFromExtension(TypeExtension typeExt, Type type) + { + var fields = type.GetFields(); + + foreach (var fi in fields) + if ((fi.Attributes & EnumField) == EnumField) + if (typeExt[fi.Name]["DefaultValue"].Value != null) + return Enum.Parse(type, fi.Name, false); + + return null; + } + + #endregion + + #region GetNullable + + public override bool GetNullable(MappingSchema mappingSchema, TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + // Check extension <Member1 Nullable='true' /> + // + var value = GetValue(typeExtension, member, "Nullable", out isSet); + + if (isSet) + return TypeExtension.ToBoolean(value); + + // Check extension <Member1 NullValue='-1' /> + // + if (GetValue(typeExtension, member, "NullValue", out isSet) != null) + return true; + + return base.GetNullable(mappingSchema, typeExtension, member, out isSet); + } + + #endregion + + #region GetNullable + + public override bool GetLazyInstance(MappingSchema mappingSchema, TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + // Check extension <Member1 Nullable='true' /> + // + var value = GetValue(typeExtension, member, "LazyInstance", out isSet); + + if (isSet) + return TypeExtension.ToBoolean(value); + + // Check extension <Member1 NullValue='-1' /> + // + if (GetValue(typeExtension, member, "LazyInstance", out isSet) != null) + return true; + + return base.GetLazyInstance(mappingSchema, typeExtension, member, out isSet); + } + + #endregion + + #region GetNullable + + public override object GetNullValue(MappingSchema mappingSchema, TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + // Check extension <Member1 NullValue='-1' /> + // + var value = GetValue(typeExtension, member, "NullValue", out isSet); + + return isSet? TypeExtension.ChangeType(value, member.Type): null; + } + + #endregion + + #region GetDbName + + public override string GetDatabaseName(Type type, ExtensionList extensions, out bool isSet) + { + var typeExt = TypeExtension.GetTypeExtension(type, extensions); + var value = typeExt.Attributes["DatabaseName"].Value; + + if (value != null) + { + isSet = true; + return value.ToString(); + } + + return base.GetDatabaseName(type, extensions, out isSet); + } + + #endregion + + #region GetOwnerName + + public override string GetOwnerName(Type type, ExtensionList extensions, out bool isSet) + { + var typeExt = TypeExtension.GetTypeExtension(type, extensions); + var value = typeExt.Attributes["OwnerName"].Value; + + if (value != null) + { + isSet = true; + return value.ToString(); + } + + return base.GetOwnerName(type, extensions, out isSet); + } + + #endregion + + #region GetTableName + + public override string GetTableName(Type type, ExtensionList extensions, out bool isSet) + { + var typeExt = TypeExtension.GetTypeExtension(type, extensions); + var value = typeExt.Attributes["TableName"].Value; + + if (value != null) + { + isSet = true; + return value.ToString(); + } + + return base.GetTableName(type, extensions, out isSet); + } + + #endregion + + #region GetPrimaryKeyOrder + + public override int GetPrimaryKeyOrder(Type type, TypeExtension typeExt, MemberAccessor member, out bool isSet) + { + var value = typeExt[member.Name]["PrimaryKey"].Value; + + if (value != null) + { + isSet = true; + return (int)TypeExtension.ChangeType(value, typeof(int)); + } + + return base.GetPrimaryKeyOrder(type, typeExt, member, out isSet); + } + + #endregion + + #region GetNonUpdatableFlag + + public override NonUpdatableAttribute GetNonUpdatableAttribute(Type type, TypeExtension typeExt, MemberAccessor member, out bool isSet) + { + var value = typeExt[member.Name]["NonUpdatable"].Value; + + if (value != null) + { + isSet = true; + return (bool)TypeExtension.ChangeType(value, typeof(bool)) ? new NonUpdatableAttribute() : null; + } + + value = typeExt[member.Name]["Identity"].Value; + + if (value != null) + { + isSet = true; + return (bool)TypeExtension.ChangeType(value, typeof(bool)) ? new IdentityAttribute() : null; + } + + return base.GetNonUpdatableAttribute(type, typeExt, member, out isSet); + } + + #endregion + + #region GetSqlIgnore + + public override bool GetSqlIgnore(TypeExtension typeExtension, MemberAccessor member, out bool isSet) + { + var value = GetValue(typeExtension, member, "SqlIgnore", out isSet); + + if (value != null) + return TypeExtension.ToBoolean(value); + + return base.GetSqlIgnore(typeExtension, member, out isSet); + } + + #endregion + + #region GetRelations + + public override List<MapRelationBase> GetRelations(MappingSchema schema, ExtensionList typeExt, Type master, Type slave, out bool isSet) + { + var relations = new List<MapRelationBase>(); + var ext = typeExt != null ? typeExt[master] : TypeExtension.Null; + + isSet = ext != TypeExtension.Null; + + if (!isSet) + return relations; + + var ta = TypeAccessor.GetAccessor(master); + + foreach (var mex in ext.Members.Values) + { + var relationInfos = mex.Attributes[TypeExtension.NodeName.Relation]; + + if (relationInfos == AttributeExtensionCollection.Null) + continue; + + var destinationTypeName = relationInfos[0][TypeExtension.AttrName.DestinationType, string.Empty].ToString(); + var destinationType = slave; + var ma = ta[mex.Name]; + var toMany = TypeHelper.IsSameOrParent(typeof(IEnumerable), ma.Type); + + if (destinationTypeName == string.Empty) + { + if (toMany) + throw new InvalidOperationException("Destination type should be set for enumerable relations: " + ma.Type.FullName + "." + ma.Name); + + destinationType = ma.Type; + } + else + { + if (!destinationTypeName.Contains(",")) + destinationTypeName += ", " + ta.OriginalType.Assembly.FullName; + + try + { + destinationType = Type.GetType(destinationTypeName, true); + } + catch (TypeLoadException ex) + { + throw new InvalidOperationException( + "Unable to load type by name: " + destinationTypeName + + "\n may be assembly is not specefied, please see Type.GetType(string typeName) documentation", + ex); + } + } + + if (slave != null && !TypeHelper.IsSameOrParent(slave, destinationType)) + continue; + + var masterIndexFields = new List<string>(); + var slaveIndexFields = new List<string>(); + + foreach (var ae in relationInfos[0].Attributes[TypeExtension.NodeName.MasterIndex]) + masterIndexFields.Add(ae[TypeExtension.AttrName.Name].ToString()); + + foreach (var ae in relationInfos[0].Attributes[TypeExtension.NodeName.SlaveIndex]) + slaveIndexFields.Add(ae[TypeExtension.AttrName.Name].ToString()); + + + if (slaveIndexFields.Count == 0) + { + var accessor = toMany ? ta : TypeAccessor.GetAccessor(destinationType); + var tex = TypeExtension.GetTypeExtension(accessor.Type, typeExt); + + slaveIndexFields = GetPrimaryKeyFields(schema, accessor, tex); + } + + if (slaveIndexFields.Count == 0) + throw new InvalidOperationException("Slave index is not set for relation: " + ma.Type.FullName + "." + ma.Name); + + var slaveIndex = new MapIndex(slaveIndexFields.ToArray()); + var masterIndex = masterIndexFields.Count > 0 ? new MapIndex(masterIndexFields.ToArray()) : slaveIndex; + var mapRelation = new MapRelationBase(destinationType, slaveIndex, masterIndex, mex.Name); + + relations.Add(mapRelation); + + } + + isSet = relations.Count > 0; + return relations; + } + + #endregion + + #region GetAssociation + + public override Association GetAssociation(TypeExtension typeExtension, MemberAccessor member) + { + if (typeExtension == TypeExtension.Null) + return null; + + var mex = typeExtension[member.Name]; + + if (mex == MemberExtension.Null) + return null; + + var attrs = mex.Attributes[TypeExtension.NodeName.Association]; + + if (attrs == AttributeExtensionCollection.Null) + return null; + + return new Association( + member, + Association.ParseKeys(attrs[0]["ThisKey", string.Empty].ToString()), + Association.ParseKeys(attrs[0]["OtherKey", string.Empty].ToString()), + attrs[0]["Storage", string.Empty].ToString(), + TypeExtension.ToBoolean(attrs[0]["Storage", "True"], true)); + } + + #endregion + + #region GetInheritanceMapping + + public override InheritanceMappingAttribute[] GetInheritanceMapping(Type type, TypeExtension typeExtension) + { + var extList = typeExtension.Attributes["InheritanceMapping"]; + + if (extList == AttributeExtensionCollection.Null) + return Array<InheritanceMappingAttribute>.Empty; + + var attrs = new InheritanceMappingAttribute[extList.Count]; + + for (var i = 0; i < extList.Count; i++) + { + var ext = extList[i]; + + attrs[i] = new InheritanceMappingAttribute + { + Code = ext["Code"], + IsDefault = TypeExtension.ToBoolean(ext["IsDefault", "False"], false), + Type = Type.GetType(Convert.ToString(ext["Type"])) + }; + } + + return attrs; + } + + #endregion + } +}