日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【译】将IDataRecord自动填充到实体的扩展方法

發布時間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【译】将IDataRecord自动填充到实体的扩展方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Mapper:

Mapper的核心功能是創建一個委托函數并映射到一個目標類的實例。此委托是使用表達式樹創建的一個lambda表達式。 在這個函數中有一個雙重循環,從 DataRecord 獲取字段并和從實體類中獲取的屬性名稱比較從而填充實體實例。 所以第一個要求就是在使用這個 Mapper?時,DataReader的字段名必須匹配將要填充類的屬性名且要填充的屬性是可寫的。 對于每個映射屬性檢查源和目標類型,不管他們是否為空,不管他們是否需要轉換。 我們需要的所有信息中存在 SchemaTable,但是 IDataReader 不處理 null 值。 /// <summary> /// 從提供的 DataRecord 對象創建新委托實例。 /// </summary> /// <param name="RecordInstance">表示一個 DataRecord 實例</param> /// <returns>從提供的 DataRecord 對象創建新委托實例。</returns> /// <remarks></remarks> private static Func<Record, Target> GetInstanceCreator(Record RecordInstance) {List<MemberBinding> Bindings = new List<MemberBinding>();Type TargetType = typeof(Target);Type SourceType = typeof(Record);ParameterExpression SourceInstance = Expression.Parameter(SourceType, "SourceInstance");MethodInfo GetSourcePropertyMethodExpression = SourceType.GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod();DataTable SchemaTable = ((IDataReader)RecordInstance).GetSchemaTable();//通過在目標屬性和字段在記錄中的循環檢查哪些是匹配的for (int i = 0; i <= RecordInstance.FieldCount - 1; i++){foreach (PropertyInfo TargetProperty in TargetType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {//如果屬性名和字段名稱是一樣的if (TargetProperty.Name.ToLower() == RecordInstance.GetName(i).ToLower() && TargetProperty.CanWrite) {//獲取 RecordField 的類型Type RecordFieldType = RecordInstance.GetFieldType(i);//RecordField 可空類型檢查if ((bool)(SchemaTable.Rows[i]["AllowDBNull"]) == true && RecordFieldType.IsValueType) {RecordFieldType = typeof(Nullable<>).MakeGenericType(RecordFieldType);}//為 RecordField 創建一個表達式Expression RecordFieldExpression = Expression.Call(SourceInstance, GetSourcePropertyMethodExpression, Expression.Constant(i, typeof(int)));//獲取一個表示 SourceValue 的表達式Expression SourceValueExpression = GetSourceValueExpression(RecordFieldType, RecordFieldExpression);Type TargetPropertyType = TargetProperty.PropertyType;//從 RecordField 到 TargetProperty 類型的值轉換Expression ConvertedRecordFieldExpression = GetConvertedRecordFieldExpression(RecordFieldType, SourceValueExpression, TargetPropertyType);MethodInfo TargetPropertySetter = TargetProperty.GetSetMethod();//為屬性創建綁定var BindExpression = Expression.Bind(TargetPropertySetter, ConvertedRecordFieldExpression);//將綁定添加到綁定列表 Bindings.Add(BindExpression);}}}//創建 Target 的新實例并綁定到 DataRecordMemberInitExpression Body = Expression.MemberInit(Expression.New(TargetType), Bindings);return Expression.Lambda<Func<Record, Target>>(Body, SourceInstance).Compile(); }

現在我們需要從 IDataReader 創建一個?sourceproperty。

/// <summary> /// 獲取表示 RecordField 真實值的表達式。 /// </summary> /// <param name="RecordFieldType">表示 RecordField 的類型。</param> /// <param name="RecordFieldExpression">表示 RecordField 的表達式。</param> /// <returns>表示 SourceValue 的表達式。</returns> private static Expression GetSourceValueExpression(Type RecordFieldType, Expression RecordFieldExpression) {//首先從 RecordField 取消裝箱值,以便我們可以使用它UnaryExpression UnboxedRecordFieldExpression = Expression.Convert(RecordFieldExpression, RecordFieldType);//獲取一個檢查 SourceField 為 null 值的表達式UnaryExpression NullCheckExpression = Expression.IsFalse(Expression.TypeIs(RecordFieldExpression, typeof(DBNull)));ParameterExpression Value = Expression.Variable(RecordFieldType, "Value");//獲取一個設置 TargetProperty 值的表達式Expression SourceValueExpression = Expression.Block(new ParameterExpression[] { Value }, Expression.IfThenElse(NullCheckExpression, Expression.Assign(Value, UnboxedRecordFieldExpression),Expression.Assign(Value, Expression.Constant(GetDefaultValue(RecordFieldType), RecordFieldType))), Expression.Convert(Value, RecordFieldType));return SourceValueExpression; }

現在把源轉換到目標屬性。

如果它們相同,只需要在裝箱之前將源對象分配給目標屬性。如果他們不同我們還需要將源對象強制轉換為目標類型。

還有一個特殊情況,需要處理這里。沒有操作符為原始類型轉換為字符串。所以如果我們試試這個函數將拋出異常。這是通過調用?ToString?方法處理源。

/// <summary> /// Gets an expression representing the recordField converted to the TargetPropertyType /// </summary> /// <param name="RecordFieldType">The Type of the RecordField</param> /// <param name="UnboxedRecordFieldExpression">An Expression representing the Unboxed RecordField value</param> /// <param name="TargetPropertyType">The Type of the TargetProperty</param> /// <returns></returns> private static Expression GetConvertedRecordFieldExpression(Type RecordFieldType, Expression UnboxedRecordFieldExpression, Type TargetPropertyType) {Expression ConvertedRecordFieldExpression = default(Expression);if (object.ReferenceEquals(TargetPropertyType, RecordFieldType)){//Just assign the unboxed expressionConvertedRecordFieldExpression = UnboxedRecordFieldExpression;}else if (object.ReferenceEquals(TargetPropertyType, typeof(string))){//There are no casts from primitive types to String.//And Expression.Convert Method (Expression, Type, MethodInfo) only works with static methods.ConvertedRecordFieldExpression = Expression.Call(UnboxedRecordFieldExpression, RecordFieldType.GetMethod("ToString", Type.EmptyTypes));}else{//Using Expression.Convert works wherever you can make an explicit or implicit cast.//But it casts OR unboxes an object, therefore the double cast. First unbox to the SourceType and then cast to the TargetType//It also doesn't convert a numerical type to a String or date, this will throw an exception.ConvertedRecordFieldExpression = Expression.Convert(UnboxedRecordFieldExpression, TargetPropertyType);}return ConvertedRecordFieldExpression; }

為了使用其更快,我們將使用緩存

/// <summary> /// A Singleton construct that returns a precompiled delegate if it exists, otherwise it will create one /// </summary> /// <param name="RecordInstance"></param> /// <returns></returns> static internal Func<Record, Target> GetCreator(Record RecordInstance) {if (_Creator == null){lock (SyncRoot){if (_Creator == null){//Get Creator on first access_Creator = GetInstanceCreator(RecordInstance);}}}return _Creator; }

?使用示例:

公有方法包括兩個簡單的擴展方法,所以?IDataRecord?所以使用映射器是很容易的。

/// <summary> /// ExtensionMethod that creates a List<Target> from the supplied IDataReader /// </summary> /// <param name="Reader"></param> /// <returns></returns> public static List<Target> ToList<Target>(this IDataReader Reader) where Target : class, new() {List<Target> List = new List<Target>();while (Reader.Read()){List.Add(CreateInstance<Target>(Reader));}return List; }/// <summary> /// ExtensionMethod that Creates an instance<Target>) from a DataRecord. /// </summary> /// <param name="Record">The DataRecord containing the values to set on new instance</param> /// <returns>An instance of Target class</returns> public static Target CreateInstance<Target>( this IDataRecord Record) where Target : class, new() {return (Mapper<IDataRecord, Target>.GetCreator(Record))(Record); } 可以像這樣使用它:Reader.CreateInstance<MyClassInstance>Reader.ToList<MyClass>()

總結

以上是生活随笔為你收集整理的【译】将IDataRecord自动填充到实体的扩展方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。