You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	using compiled delegate instead of reflection in Marr
This commit is contained in:
		| @@ -74,7 +74,7 @@ namespace Marr.Data | ||||
|             { | ||||
|                 _columns = _repos.GetColumns(entityType); | ||||
|             } | ||||
|              | ||||
|  | ||||
|             _relationships = _repos.GetRelationships(entityType); | ||||
|             _children = new List<EntityGraph>(); | ||||
|             Member = relationship != null ? relationship.Member : null; | ||||
| @@ -161,7 +161,7 @@ namespace Marr.Data | ||||
|         { | ||||
|             get { return _children; } | ||||
|         } | ||||
|          | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds an entity to the appropriate place in the object graph. | ||||
|         /// </summary> | ||||
| @@ -184,13 +184,13 @@ namespace Marr.Data | ||||
|             } | ||||
|             else // RelationTypes.One | ||||
|             { | ||||
|                 _repos.ReflectionStrategy.SetFieldValue(_parent._entity, _relationship.Member.Name, entityInstance); | ||||
|                 _relationship.Setter(_parent._entity, entityInstance); | ||||
|             } | ||||
|  | ||||
|             EntityReference entityRef = new EntityReference(entityInstance); | ||||
|             _entityReferences.Add(GroupingKeyColumns.GroupingKey, entityRef); | ||||
|  | ||||
|             InitOneToManyChildLists(entityRef);            | ||||
|             InitOneToManyChildLists(entityRef); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
| @@ -199,9 +199,9 @@ namespace Marr.Data | ||||
|         public void AddParentReference() | ||||
|         { | ||||
|             var parentReference = FindParentReference(); | ||||
|             _repos.ReflectionStrategy.SetFieldValue(_parent._entity, _relationship.Member.Name, parentReference); | ||||
|             _relationship.Setter(_parent._entity, parentReference); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Concatenates the values of the GroupingKeys property and compares them | ||||
|         /// against the LastKeyGroup property.  Returns true if the values are different, | ||||
| @@ -296,8 +296,8 @@ namespace Marr.Data | ||||
|                     try | ||||
|                     { | ||||
|                         IList list = (IList)_repos.ReflectionStrategy.CreateInstance(relationship.MemberType); | ||||
|                         _repos.ReflectionStrategy.SetFieldValue(entityRef.Entity, relationship.Member.Name, list); | ||||
|                          | ||||
|                         relationship.Setter(entityRef.Entity, list); | ||||
|  | ||||
|                         // Save a reference to each 1-M list | ||||
|                         entityRef.AddChildList(relationship.Member.Name, list); | ||||
|                     } | ||||
| @@ -398,13 +398,13 @@ public struct KeyGroupInfo | ||||
|         _hasNullKey = hasNullKey; | ||||
|     } | ||||
|  | ||||
|     public string GroupingKey  | ||||
|     {  | ||||
|         get { return _groupingKey; }  | ||||
|     public string GroupingKey | ||||
|     { | ||||
|         get { return _groupingKey; } | ||||
|     } | ||||
|  | ||||
|     public bool HasNullKey  | ||||
|     public bool HasNullKey | ||||
|     { | ||||
|         get { return _hasNullKey; }  | ||||
|         get { return _hasNullKey; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -53,8 +53,8 @@ namespace Marr.Data | ||||
|             TypeConverters = new Dictionary<Type, IConverter>(); | ||||
|  | ||||
|             // Register a default IReflectionStrategy | ||||
|             ReflectionStrategy = new CachedReflectionStrategy(); | ||||
|              | ||||
|             ReflectionStrategy = new SimpleReflectionStrategy(); | ||||
|  | ||||
|             // Register a default type converter for Enums | ||||
|             TypeConverters.Add(typeof(Enum), new Converters.EnumStringConverter()); | ||||
|  | ||||
| @@ -180,7 +180,7 @@ namespace Marr.Data | ||||
|  | ||||
|             return Relationships[type]; | ||||
|         } | ||||
|          | ||||
|  | ||||
|         #endregion | ||||
|  | ||||
|         #region - Reflection Strategy - | ||||
| @@ -190,6 +190,7 @@ namespace Marr.Data | ||||
|         /// By default the CachedReflector will be used, which provides a performance increase over the SimpleReflector.   | ||||
|         /// However, the SimpleReflector can be used in Medium Trust enviroments. | ||||
|         /// </summary> | ||||
|         ///  | ||||
|         public IReflectionStrategy ReflectionStrategy { get; set; } | ||||
|  | ||||
|         #endregion | ||||
|   | ||||
| @@ -14,11 +14,9 @@ You should have received a copy of the GNU Lesser General Public | ||||
| License along with this library. If not, see <http://www.gnu.org/licenses/>. */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Data; | ||||
| using System.Reflection; | ||||
| using Marr.Data.Converters; | ||||
| using Marr.Data.Reflection; | ||||
|  | ||||
| namespace Marr.Data.Mapping | ||||
| { | ||||
| @@ -27,6 +25,7 @@ namespace Marr.Data.Mapping | ||||
|     /// </summary> | ||||
|     public class ColumnMap | ||||
|     { | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Creates a column map with an empty ColumnInfo object. | ||||
|         /// </summary> | ||||
| @@ -38,32 +37,34 @@ namespace Marr.Data.Mapping | ||||
|         public ColumnMap(MemberInfo member, IColumnInfo columnInfo) | ||||
|         { | ||||
|             FieldName = member.Name; | ||||
|             ColumnInfo = columnInfo; | ||||
|  | ||||
|             // If the column name is not specified, the field name will be used. | ||||
|             if (string.IsNullOrEmpty(columnInfo.Name)) | ||||
|                 columnInfo.Name = member.Name; | ||||
|  | ||||
|             FieldType = ReflectionHelper.GetMemberType(member); | ||||
|  | ||||
|             Type paramNetType = FieldType; | ||||
|             MapRepository repository = MapRepository.Instance; | ||||
|  | ||||
|             IConverter converter = repository.GetConverter(FieldType); | ||||
|             if (converter != null) | ||||
|             Converter = MapRepository.Instance.GetConverter(FieldType); | ||||
|             if (Converter != null) | ||||
|             { | ||||
|                 // Handle conversions | ||||
|                 paramNetType = converter.DbType; | ||||
|                 paramNetType = Converter.DbType; | ||||
|             } | ||||
|  | ||||
|             // Get database specific DbType and store with column map in cache     | ||||
|             DBType = repository.DbTypeBuilder.GetDbType(paramNetType); | ||||
|             DBType = MapRepository.Instance.DbTypeBuilder.GetDbType(paramNetType); | ||||
|  | ||||
|             ColumnInfo = columnInfo; | ||||
|             Getter = MapRepository.Instance.ReflectionStrategy.BuildGetter(member.DeclaringType, FieldName); | ||||
|             Setter = MapRepository.Instance.ReflectionStrategy.BuildSetter(member.DeclaringType, FieldName); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         public string FieldName { get; set; } | ||||
|         public Type FieldType { get; set; } | ||||
|         public Enum DBType { get; set; } | ||||
|         public IColumnInfo ColumnInfo { get; set; } | ||||
|  | ||||
|         public GetterDelegate Getter { get; private set; } | ||||
|         public SetterDelegate Setter { get; private set; } | ||||
|         public IConverter Converter { get; private set; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -53,13 +53,15 @@ namespace Marr.Data.Mapping | ||||
|                     object dbValue = reader.GetValue(ordinal); | ||||
|  | ||||
|                     // Handle conversions | ||||
|                     IConverter conversion = _repos.GetConverter(dataMap.FieldType); | ||||
|                     if (conversion != null) | ||||
|                     if (dataMap.Converter != null) | ||||
|                     { | ||||
|                         dbValue = conversion.FromDB(dataMap, dbValue); | ||||
|                         dbValue = dataMap.Converter.FromDB(dataMap, dbValue); | ||||
|                     } | ||||
|  | ||||
|                     _repos.ReflectionStrategy.SetFieldValue(ent, dataMap.FieldName, dbValue); | ||||
|                     if (dbValue != DBNull.Value) | ||||
|                     { | ||||
|                         dataMap.Setter(ent, dbValue); | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
| @@ -91,9 +93,9 @@ namespace Marr.Data.Mapping | ||||
|                 var relationships = _repos.Relationships[entType]; | ||||
|                 foreach (var rel in relationships.Where(r => r.IsLazyLoaded)) | ||||
|                 { | ||||
|                     ILazyLoaded lazyLoaded = (ILazyLoaded)rel.LazyLoaded.Clone(); | ||||
|                     var lazyLoaded = (ILazyLoaded)rel.LazyLoaded.Clone(); | ||||
|                     lazyLoaded.Prepare(dbCreate, ent); | ||||
|                     _repos.ReflectionStrategy.SetFieldValue(ent, rel.Member.Name, lazyLoaded); | ||||
|                     rel.Setter(ent, lazyLoaded); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -138,21 +140,18 @@ namespace Marr.Data.Mapping | ||||
|                 param.Size = columnMap.ColumnInfo.Size; | ||||
|                 param.Direction = columnMap.ColumnInfo.ParamDirection; | ||||
|  | ||||
|                 object val = _repos.ReflectionStrategy.GetFieldValue(entity, columnMap.FieldName); | ||||
|                 object val = columnMap.Getter(entity); | ||||
|  | ||||
|                 param.Value = val == null ? DBNull.Value : val; // Convert nulls to DBNulls | ||||
|                 param.Value = val ?? DBNull.Value; // Convert nulls to DBNulls | ||||
|  | ||||
|                 var repos = MapRepository.Instance; | ||||
|  | ||||
|                 IConverter conversion = repos.GetConverter(columnMap.FieldType); | ||||
|                 if (conversion != null) | ||||
|                 if (columnMap.Converter != null) | ||||
|                 { | ||||
|                     param.Value = conversion.ToDB(param.Value); | ||||
|                     param.Value = columnMap.Converter.ToDB(param.Value); | ||||
|                 } | ||||
|  | ||||
|                 // Set the appropriate DbType property depending on the parameter type | ||||
|                 // Note: the columnMap.DBType property was set when the ColumnMap was created | ||||
|                 repos.DbTypeBuilder.SetDbType(param, columnMap.DBType); | ||||
|                 MapRepository.Instance.DbTypeBuilder.SetDbType(param, columnMap.DBType); | ||||
|  | ||||
|                 _db.Command.Parameters.Add(param); | ||||
|             } | ||||
| @@ -166,7 +165,7 @@ namespace Marr.Data.Mapping | ||||
|             foreach (ColumnMap dataMap in mappings) | ||||
|             { | ||||
|                 object output = _db.Command.Parameters[dataMap.ColumnInfo.Name].Value; | ||||
|                 _repos.ReflectionStrategy.SetFieldValue(entity, dataMap.FieldName, output); | ||||
|                 dataMap.Setter(entity, output); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -177,7 +176,7 @@ namespace Marr.Data.Mapping | ||||
|         { | ||||
|             foreach (ColumnMap dataMap in mappings) | ||||
|             { | ||||
|                 _repos.ReflectionStrategy.SetFieldValue(entity, dataMap.FieldName, Convert.ChangeType(value, dataMap.FieldType)); | ||||
|                 dataMap.Setter(entity, Convert.ChangeType(value, dataMap.FieldType)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -14,17 +14,13 @@ You should have received a copy of the GNU Lesser General Public | ||||
| License along with this library. If not, see <http://www.gnu.org/licenses/>. */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Reflection; | ||||
| using Marr.Data.Reflection; | ||||
|  | ||||
| namespace Marr.Data.Mapping | ||||
| { | ||||
|     public class Relationship | ||||
|     { | ||||
|         private IRelationshipInfo _relationshipInfo; | ||||
|         private MemberInfo _member; | ||||
|         private ILazyLoaded _lazyLoaded; | ||||
|  | ||||
|         public Relationship(MemberInfo member) | ||||
|             : this(member, new RelationshipInfo()) | ||||
| @@ -32,14 +28,14 @@ namespace Marr.Data.Mapping | ||||
|  | ||||
|         public Relationship(MemberInfo member, IRelationshipInfo relationshipInfo) | ||||
|         { | ||||
|             _member = member; | ||||
|             Member = member; | ||||
|  | ||||
|             Type memberType = ReflectionHelper.GetMemberType(member); | ||||
|             MemberType = ReflectionHelper.GetMemberType(member); | ||||
|  | ||||
|             // Try to determine the RelationshipType | ||||
|             if (relationshipInfo.RelationType == RelationshipTypes.AutoDetect) | ||||
|             { | ||||
|                 if (typeof(System.Collections.ICollection).IsAssignableFrom(memberType)) | ||||
|                 if (typeof(System.Collections.ICollection).IsAssignableFrom(MemberType)) | ||||
|                 { | ||||
|                     relationshipInfo.RelationType = RelationshipTypes.Many; | ||||
|                 } | ||||
| @@ -54,67 +50,48 @@ namespace Marr.Data.Mapping | ||||
|             { | ||||
|                 if (relationshipInfo.RelationType == RelationshipTypes.Many) | ||||
|                 { | ||||
|                     if (memberType.IsGenericType) | ||||
|                     if (MemberType.IsGenericType) | ||||
|                     { | ||||
|                         // Assume a Collection<T> or List<T> and return T | ||||
|                         relationshipInfo.EntityType = memberType.GetGenericArguments()[0]; | ||||
|                         relationshipInfo.EntityType = MemberType.GetGenericArguments()[0]; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         throw new ArgumentException(string.Format( | ||||
|                             "The DataMapper could not determine the RelationshipAttribute EntityType for {0}.", | ||||
|                             memberType.Name)); | ||||
|                             MemberType.Name)); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     relationshipInfo.EntityType = memberType; | ||||
|                     relationshipInfo.EntityType = MemberType; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             _relationshipInfo = relationshipInfo; | ||||
|             RelationshipInfo = relationshipInfo; | ||||
|  | ||||
|  | ||||
|  | ||||
|             Setter = MapRepository.Instance.ReflectionStrategy.BuildSetter(member.DeclaringType, member.Name); | ||||
|         } | ||||
|  | ||||
|         public IRelationshipInfo RelationshipInfo | ||||
|         { | ||||
|             get { return _relationshipInfo; } | ||||
|         } | ||||
|         public IRelationshipInfo RelationshipInfo { get; private set; } | ||||
|  | ||||
|         public MemberInfo Member | ||||
|         { | ||||
|             get { return _member; } | ||||
|         } | ||||
|         public MemberInfo Member { get; private set; } | ||||
|  | ||||
|         public Type MemberType | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 // Assumes that a relationship can only have a member type of Field or Property | ||||
|                 if (Member.MemberType == MemberTypes.Field) | ||||
|                     return (Member as FieldInfo).FieldType; | ||||
|                 else | ||||
|                     return (Member as PropertyInfo).PropertyType; | ||||
|             } | ||||
|         } | ||||
|         public Type MemberType { get; private set; } | ||||
|  | ||||
|         public bool IsLazyLoaded | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return _lazyLoaded != null; | ||||
|                 return LazyLoaded != null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public ILazyLoaded LazyLoaded | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return _lazyLoaded; | ||||
|             } | ||||
|             set | ||||
|             { | ||||
|                 _lazyLoaded = value; | ||||
|             } | ||||
|         } | ||||
|         public ILazyLoaded LazyLoaded { get; set; } | ||||
|  | ||||
|         public GetterDelegate Getter { get; set; } | ||||
|         public SetterDelegate Setter { get; set; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -39,17 +39,10 @@ | ||||
|     <WarningLevel>4</WarningLevel> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <Reference Include="Fasterflect, Version=2.1.3.0, Culture=neutral, PublicKeyToken=38d18473284c1ca7, processorArchitecture=MSIL"> | ||||
|       <SpecificVersion>False</SpecificVersion> | ||||
|       <HintPath>..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll</HintPath> | ||||
|     </Reference> | ||||
|     <Reference Include="System" /> | ||||
|     <Reference Include="System.Core"> | ||||
|       <RequiredTargetFramework>3.5</RequiredTargetFramework> | ||||
|     </Reference> | ||||
|     <Reference Include="System.Data.DataSetExtensions"> | ||||
|       <RequiredTargetFramework>3.5</RequiredTargetFramework> | ||||
|     </Reference> | ||||
|     <Reference Include="System.Data" /> | ||||
|     <Reference Include="System.Xml" /> | ||||
|   </ItemGroup> | ||||
| @@ -134,7 +127,6 @@ | ||||
|     <Compile Include="QGen\WhereBuilder.cs" /> | ||||
|     <Compile Include="Reflection\IReflectionStrategy.cs" /> | ||||
|     <Compile Include="Reflection\SimpleReflectionStrategy.cs" /> | ||||
|     <Compile Include="Reflection\CachedReflectionStrategy.cs" /> | ||||
|     <Compile Include="Reflection\ReflectionHelper.cs" /> | ||||
|     <Compile Include="SqlModesEnum.cs" /> | ||||
|   </ItemGroup> | ||||
|   | ||||
| @@ -14,9 +14,6 @@ You should have received a copy of the GNU Lesser General Public | ||||
| License along with this library. If not, see <http://www.gnu.org/licenses/>. */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Data; | ||||
| using System.Data.Common; | ||||
| using Marr.Data.Converters; | ||||
|   | ||||
| @@ -1,99 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using Fasterflect; | ||||
|  | ||||
| namespace Marr.Data.Reflection | ||||
| { | ||||
|     public class CachedReflectionStrategy : IReflectionStrategy | ||||
|     { | ||||
|         private static readonly Dictionary<string, MemberInfo> MemberCache = new Dictionary<string, MemberInfo>(); | ||||
|         private static MemberInfo GetMember(Type entityType, string name) | ||||
|         { | ||||
|             MemberInfo member; | ||||
|             var key = entityType.FullName + name; | ||||
|             if (!MemberCache.TryGetValue(key, out member)) | ||||
|             { | ||||
|                 member = entityType.GetMember(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; | ||||
|                 MemberCache[key] = member; | ||||
|             } | ||||
|  | ||||
|             return member; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets an entity field value by name to the passed in 'val'. | ||||
|         /// </summary> | ||||
|         public void SetFieldValue<T>(T entity, string fieldName, object val) | ||||
|         { | ||||
|             MemberInfo member = GetMember(entity.GetType(), fieldName); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 // Handle DB null values | ||||
|                 if (val == DBNull.Value) | ||||
|                 { | ||||
|                     if (member.MemberType == MemberTypes.Field) | ||||
|                     { | ||||
|                         entity.SetFieldValue(member.Name, ReflectionHelper.GetDefaultValue(((FieldInfo)member).FieldType)); | ||||
|                     } | ||||
|                     else if (member.MemberType == MemberTypes.Property) | ||||
|                     { | ||||
|                         var pi = (PropertyInfo)member; | ||||
|                         if (pi.CanWrite) | ||||
|                         { | ||||
|                             entity.SetPropertyValue(member.Name, ReflectionHelper.GetDefaultValue(((PropertyInfo)member).PropertyType)); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (member.MemberType == MemberTypes.Field) | ||||
|                     { | ||||
|                         entity.SetFieldValue(member.Name, val); | ||||
|                     } | ||||
|                     else if (member.MemberType == MemberTypes.Property && ((PropertyInfo)member).CanWrite) | ||||
|                     { | ||||
|                         member.Set(entity, val); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 string msg = string.Format("The DataMapper was unable to load the following field: {0}.  \nDetails: {1}", fieldName, ex.Message); | ||||
|                 throw new DataMappingException(msg, ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets an entity field value by name. | ||||
|         /// </summary> | ||||
|         public object GetFieldValue(object entity, string fieldName) | ||||
|         { | ||||
|             MemberInfo member = GetMember(entity.GetType(), fieldName); | ||||
|  | ||||
|  | ||||
|             if (member.MemberType == MemberTypes.Field) | ||||
|             { | ||||
|                 return entity.GetFieldValue(member.Name); | ||||
|             } | ||||
|  | ||||
|             if (member.MemberType == MemberTypes.Property && ((PropertyInfo)member).CanRead) | ||||
|             { | ||||
|                 return entity.GetPropertyValue(member.Name); | ||||
|             } | ||||
|  | ||||
|             throw new DataMappingException(string.Format("The DataMapper could not get the value for {0}.{1}.", entity.GetType().Name, fieldName)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Instantiantes a type using the Fasterflect library for increased speed. | ||||
|         /// </summary> | ||||
|         /// <param name="type"></param> | ||||
|         /// <returns></returns> | ||||
|         public object CreateInstance(Type type) | ||||
|         { | ||||
|             return type.CreateInstance(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +1,17 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
|  | ||||
| namespace Marr.Data.Reflection | ||||
| { | ||||
|     public interface IReflectionStrategy | ||||
|     { | ||||
|         void SetFieldValue<T>(T entity, string fieldName, object val); | ||||
|         object GetFieldValue(object entity, string fieldName); | ||||
|  | ||||
|         GetterDelegate BuildGetter(Type type, string memberName); | ||||
|         SetterDelegate BuildSetter(Type type, string memberName); | ||||
|  | ||||
|         object CreateInstance(Type type); | ||||
|     } | ||||
|  | ||||
|     public delegate void SetterDelegate(object instance, object value); | ||||
|     public delegate object GetterDelegate(object instance); | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq.Expressions; | ||||
| using System.Reflection; | ||||
|  | ||||
| namespace Marr.Data.Reflection | ||||
| @@ -8,6 +9,8 @@ namespace Marr.Data.Reflection | ||||
|     { | ||||
|  | ||||
|         private static readonly Dictionary<string, MemberInfo> MemberCache = new Dictionary<string, MemberInfo>(); | ||||
|         private static readonly Dictionary<string, GetterDelegate> GetterCache = new Dictionary<string, GetterDelegate>(); | ||||
|         private static readonly Dictionary<string, SetterDelegate> SetterCache = new Dictionary<string, SetterDelegate>(); | ||||
|  | ||||
|  | ||||
|         private static MemberInfo GetMember(Type entityType, string name) | ||||
| @@ -23,54 +26,6 @@ namespace Marr.Data.Reflection | ||||
|             return member; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets an entity field value by name to the passed in 'val'. | ||||
|         /// </summary> | ||||
|         public void SetFieldValue<T>(T entity, string fieldName, object val) | ||||
|         { | ||||
|             var member = GetMember(entity.GetType(), fieldName); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 // Handle DB null values | ||||
|                 if (val == DBNull.Value) | ||||
|                 { | ||||
|                     if (member.MemberType == MemberTypes.Field) | ||||
|                     { | ||||
|                         (member as FieldInfo).SetValue(entity, | ||||
|                                                        ReflectionHelper.GetDefaultValue((member as FieldInfo).FieldType)); | ||||
|                     } | ||||
|                     else if (member.MemberType == MemberTypes.Property) | ||||
|                     { | ||||
|                         var pi = (member as PropertyInfo); | ||||
|                         if (pi.CanWrite) | ||||
|                             (member as PropertyInfo).SetValue(entity, | ||||
|                                                               ReflectionHelper.GetDefaultValue( | ||||
|                                                                   (member as PropertyInfo).PropertyType), null); | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (member.MemberType == MemberTypes.Field) | ||||
|                         (member as FieldInfo).SetValue(entity, val); | ||||
|  | ||||
|                     else if (member.MemberType == MemberTypes.Property) | ||||
|                     { | ||||
|                         var pi = (member as PropertyInfo); | ||||
|                         if (pi.CanWrite) | ||||
|                             (member as PropertyInfo).SetValue(entity, val, null); | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 string msg = string.Format("The DataMapper was unable to load the following field: {0}.  \nDetails: {1}", fieldName, ex.Message); | ||||
|                 throw new DataMappingException(msg, ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets an entity field value by name. | ||||
|         /// </summary> | ||||
| @@ -84,14 +39,14 @@ namespace Marr.Data.Reflection | ||||
|             } | ||||
|             if (member.MemberType == MemberTypes.Property) | ||||
|             { | ||||
|                 if ((member as PropertyInfo).CanRead) | ||||
|                     return (member as PropertyInfo).GetValue(entity, null); | ||||
|                 return BuildGetter(entity.GetType(), fieldName)(entity); | ||||
|             } | ||||
|             throw new DataMappingException(string.Format("The DataMapper could not get the value for {0}.{1}.", entity.GetType().Name, fieldName)); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Instantiantes a type using the FastReflector library for increased speed. | ||||
|         /// Instantiates a type using the FastReflector library for increased speed. | ||||
|         /// </summary> | ||||
|         /// <param name="type"></param> | ||||
|         /// <returns></returns> | ||||
| @@ -99,5 +54,92 @@ namespace Marr.Data.Reflection | ||||
|         { | ||||
|             return Activator.CreateInstance(type); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|         public GetterDelegate BuildGetter(Type type, string memberName) | ||||
|         { | ||||
|             GetterDelegate getter; | ||||
|             var key = type.FullName + memberName; | ||||
|             if (!GetterCache.TryGetValue(key, out getter)) | ||||
|             { | ||||
|                 getter = GetPropertyGetter((PropertyInfo)GetMember(type, memberName)); | ||||
|             } | ||||
|  | ||||
|             return getter; | ||||
|         } | ||||
|  | ||||
|         public SetterDelegate BuildSetter(Type type, string memberName) | ||||
|         { | ||||
|             SetterDelegate setter; | ||||
|             var key = type.FullName + memberName; | ||||
|             if (!SetterCache.TryGetValue(key, out setter)) | ||||
|             { | ||||
|                 setter = GetPropertySetter((PropertyInfo)GetMember(type, memberName)); | ||||
|             } | ||||
|  | ||||
|             return setter; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         private static SetterDelegate GetPropertySetter(PropertyInfo propertyInfo) | ||||
|         { | ||||
|             var propertySetMethod = propertyInfo.GetSetMethod(); | ||||
|             if (propertySetMethod == null) return null; | ||||
|  | ||||
| #if NO_EXPRESSIONS | ||||
|             return (o, convertedValue) => | ||||
|             { | ||||
|                 propertySetMethod.Invoke(o, new[] { convertedValue }); | ||||
|                 return; | ||||
|             }; | ||||
| #else | ||||
|             var instance = Expression.Parameter(typeof(object), "i"); | ||||
|             var argument = Expression.Parameter(typeof(object), "a"); | ||||
|  | ||||
|             var instanceParam = Expression.Convert(instance, propertyInfo.DeclaringType); | ||||
|             var valueParam = Expression.Convert(argument, propertyInfo.PropertyType); | ||||
|  | ||||
|             var setterCall = Expression.Call(instanceParam, propertyInfo.GetSetMethod(), valueParam); | ||||
|  | ||||
|             return Expression.Lambda<SetterDelegate>(setterCall, instance, argument).Compile(); | ||||
| #endif | ||||
|         } | ||||
|  | ||||
|         private static GetterDelegate GetPropertyGetter(PropertyInfo propertyInfo) | ||||
|         { | ||||
|  | ||||
|             var getMethodInfo = propertyInfo.GetGetMethod(); | ||||
|             if (getMethodInfo == null) return null; | ||||
|  | ||||
| #if NO_EXPRESSIONS | ||||
| 			return o => propertyInfo.GetGetMethod().Invoke(o, new object[] { }); | ||||
| #else | ||||
|             try | ||||
|             { | ||||
|                 var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam"); | ||||
|                 var instanceParam = Expression.Convert(oInstanceParam, propertyInfo.DeclaringType); | ||||
|  | ||||
|                 var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo); | ||||
|                 var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object)); | ||||
|  | ||||
|                 var propertyGetFn = Expression.Lambda<GetterDelegate> | ||||
|                     ( | ||||
|                         oExprCallPropertyGetFn, | ||||
|                         oInstanceParam | ||||
|                     ).Compile(); | ||||
|  | ||||
|                 return propertyGetFn; | ||||
|  | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 Console.Write(ex.Message); | ||||
|                 throw; | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,7 @@ using NzbDrone.Core.Datastore.Migration.Framework; | ||||
|  | ||||
| namespace NzbDrone.Core.Test.Framework | ||||
| { | ||||
|     [Category("DbTest")] | ||||
|     public abstract class DbTest<TSubject, TModel> : DbTest | ||||
|         where TSubject : class | ||||
|         where TModel : ModelBase, new() | ||||
|   | ||||
| @@ -123,6 +123,7 @@ | ||||
|     <Compile Include="Datastore\ObjectDatabaseFixture.cs" /> | ||||
|     <Compile Include="Datastore\PagingSpecExtenstionsTests\ToSortDirectionFixture.cs" /> | ||||
|     <Compile Include="Datastore\PagingSpecExtenstionsTests\PagingOffsetFixture.cs" /> | ||||
|     <Compile Include="Datastore\ReflectionStrategyFixture\Benchmarks.cs" /> | ||||
|     <Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" /> | ||||
|     <Compile Include="Download\DownloadClientTests\NzbgetProviderTests\DownloadNzbFixture.cs" /> | ||||
|     <Compile Include="Download\DownloadClientTests\NzbgetProviderTests\QueueFixture.cs" /> | ||||
|   | ||||
| @@ -18,6 +18,7 @@ namespace NzbDrone.Core.Datastore | ||||
|  | ||||
|         static DbFactory() | ||||
|         { | ||||
|             MapRepository.Instance.ReflectionStrategy = new SimpleReflectionStrategy(); | ||||
|             TableMapping.Map(); | ||||
|         } | ||||
|  | ||||
| @@ -32,9 +33,6 @@ namespace NzbDrone.Core.Datastore | ||||
|  | ||||
|             _migrationController.MigrateToLatest(connectionString, migrationType); | ||||
|  | ||||
|  | ||||
|             MapRepository.Instance.ReflectionStrategy = new DelegateReflectionStrategy(); | ||||
|  | ||||
|             return new Database(() => | ||||
|                 { | ||||
|                     var dataMapper = new DataMapper(SQLiteFactory.Instance, connectionString) | ||||
|   | ||||
| @@ -1,128 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq.Expressions; | ||||
| using System.Reflection; | ||||
| using Marr.Data.Reflection; | ||||
|  | ||||
| namespace NzbDrone.Core.Datastore | ||||
| { | ||||
|     public class DelegateReflectionStrategy : IReflectionStrategy | ||||
|     { | ||||
|         private static readonly Dictionary<string, PropertySetterDelegate> SetterCache = new Dictionary<string, PropertySetterDelegate>(); | ||||
|         private static readonly Dictionary<string, PropertyGetterDelegate> GetterCache = new Dictionary<string, PropertyGetterDelegate>(); | ||||
|         private static readonly IReflectionStrategy readStrat = new SimpleReflectionStrategy(); | ||||
|  | ||||
|         private static PropertySetterDelegate SetterFunction(Type entityType, string name) | ||||
|         { | ||||
|             PropertySetterDelegate setter; | ||||
|             var key = string.Concat(entityType.FullName, name); | ||||
|             if (!SetterCache.TryGetValue(key, out setter)) | ||||
|             { | ||||
|                 var setterMember = entityType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | ||||
|                 setter = setterMember.GetPropertySetterFn(); | ||||
|                 SetterCache[key] = setter; | ||||
|             } | ||||
|  | ||||
|             return setter; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         private static PropertyGetterDelegate GetterFunction(Type entityType, string name) | ||||
|         { | ||||
|             PropertyGetterDelegate getter; | ||||
|             var key = string.Concat(entityType.FullName, name); | ||||
|             if (!GetterCache.TryGetValue(key, out getter)) | ||||
|             { | ||||
|                 var propertyInfo = entityType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | ||||
|                 getter = propertyInfo.GetPropertyGetterFn(); | ||||
|                 GetterCache[key] = getter; | ||||
|             } | ||||
|  | ||||
|             return getter; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public void SetFieldValue<T>(T entity, string fieldName, object val) | ||||
|         { | ||||
|             SetterFunction(entity.GetType(), fieldName)(entity, val); | ||||
|         } | ||||
|  | ||||
|         public object GetFieldValue(object entity, string fieldName) | ||||
|         { | ||||
|             return readStrat.GetFieldValue(entity, fieldName); | ||||
|         } | ||||
|  | ||||
|         public object CreateInstance(Type type) | ||||
|         { | ||||
|             return Activator.CreateInstance(type); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public delegate void PropertySetterDelegate(object instance, object value); | ||||
|     public delegate object PropertyGetterDelegate(object instance); | ||||
|  | ||||
|     public static class PropertyInvoker | ||||
|     { | ||||
|         public static PropertySetterDelegate GetPropertySetterFn(this PropertyInfo propertyInfo) | ||||
|         { | ||||
|             var propertySetMethod = propertyInfo.GetSetMethod(); | ||||
|             if (propertySetMethod == null) return null; | ||||
|  | ||||
| #if NO_EXPRESSIONS | ||||
|             return (o, convertedValue) => | ||||
|             { | ||||
|                 propertySetMethod.Invoke(o, new[] { convertedValue }); | ||||
|                 return; | ||||
|             }; | ||||
| #else | ||||
|             var instance = Expression.Parameter(typeof(object), "i"); | ||||
|             var argument = Expression.Parameter(typeof(object), "a"); | ||||
|  | ||||
|             var instanceParam = Expression.Convert(instance, propertyInfo.DeclaringType); | ||||
|             var valueParam = Expression.Convert(argument, propertyInfo.PropertyType); | ||||
|  | ||||
|             var setterCall = Expression.Call(instanceParam, propertyInfo.GetSetMethod(), valueParam); | ||||
|  | ||||
|             return Expression.Lambda<PropertySetterDelegate>(setterCall, instance, argument).Compile(); | ||||
| #endif | ||||
|         } | ||||
|  | ||||
|         public static PropertyGetterDelegate GetPropertyGetterFn(this PropertyInfo propertyInfo) | ||||
|         { | ||||
|             var getMethodInfo = propertyInfo.GetGetMethod(); | ||||
|             if (getMethodInfo == null) return null; | ||||
|  | ||||
| #if NO_EXPRESSIONS | ||||
| 			return o => propertyInfo.GetGetMethod().Invoke(o, new object[] { }); | ||||
| #else | ||||
|             try | ||||
|             { | ||||
|                 var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam"); | ||||
|                 var instanceParam = Expression.Convert(oInstanceParam, propertyInfo.DeclaringType); | ||||
|  | ||||
|                 var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo); | ||||
|                 var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object)); | ||||
|  | ||||
|                 var propertyGetFn = Expression.Lambda<PropertyGetterDelegate> | ||||
|                     ( | ||||
|                         oExprCallPropertyGetFn, | ||||
|                         oInstanceParam | ||||
|                     ).Compile(); | ||||
|  | ||||
|                 return propertyGetFn; | ||||
|  | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 Console.Write(ex.Message); | ||||
|                 throw; | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -3,8 +3,6 @@ using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Marr.Data; | ||||
| using Marr.Data.Mapping; | ||||
| using NzbDrone.Common; | ||||
| using NzbDrone.Common.Serializer; | ||||
| using NzbDrone.Core.Configuration; | ||||
| using NzbDrone.Core.DataAugmentation.Scene; | ||||
| using NzbDrone.Core.Datastore.Converters; | ||||
|   | ||||
| @@ -220,7 +220,6 @@ | ||||
|     <Compile Include="Datastore\PagingSpec.cs" /> | ||||
|     <Compile Include="Datastore\PagingSpecExtensions.cs" /> | ||||
|     <Compile Include="Datastore\RelationshipExtensions.cs" /> | ||||
|     <Compile Include="Datastore\DelegateReflectionStrategy.cs" /> | ||||
|     <Compile Include="Datastore\TableMapping.cs" /> | ||||
|     <Compile Include="DecisionEngine\DownloadDecision.cs" /> | ||||
|     <Compile Include="DecisionEngine\IRejectWithReason.cs" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user