using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace RDH.Data { public static partial class SqlMapper { #region 扩展一对多查询 #if !CSHARP30 public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) { return MultiMap( cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType); } public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) { return MultiMap( cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType); } public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) { return MultiMap( cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType); } #endif static IEnumerable MultiMap(this IDbConnection cnn, string sql, object map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType) { var results = MultiMapImpl( cnn, sql, map, param, transaction, splitOn, commandTimeout, commandType, null, null); return buffered ? results.ToList() : results; } static IEnumerable MultiMap(this IDbConnection cnn, string sql, object map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType) { var results = MultiMapImpl(cnn, sql, map, param, transaction, splitOn, commandTimeout, commandType, null, null); return buffered ? results.ToList() : results; } static IEnumerable MultiMap(this IDbConnection cnn, string sql, object map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType) { var results = MultiMapImpl( cnn, sql, map, param, transaction, splitOn, commandTimeout, commandType, null, null); return buffered ? results.ToList() : results; } internal static IEnumerable MultiMapImpl( this IDbConnection cnn, string sql, object map, object param, IDbTransaction transaction, string splitOn, int? commandTimeout, CommandType? commandType, IDataReader reader, Identity identity) { identity = identity ?? new Identity(sql, commandType, cnn, typeof(TFirst), (object)param == null ? null : ((object)param).GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh), typeof(TEighth), typeof(TNinth), typeof(TTenth) }); CacheInfo cinfo = GetCacheInfo(identity); IDbCommand ownedCommand = null; IDataReader ownedReader = null; try { if (reader == null) { ownedCommand = SetupCommand(cnn, transaction, sql, cinfo.ParamReader, (object)param, commandTimeout, commandType); ownedReader = ownedCommand.ExecuteReader(); reader = ownedReader; } Func deserializer = null; Func[] otherDeserializers = null; Action cacheDeserializers = () => { var deserializers = GenerateDeserializers(new Type[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh), typeof(TEighth), typeof(TNinth), typeof(TTenth) }, splitOn, reader); deserializer = cinfo.Deserializer = deserializers[0]; otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray(); SetQueryCache(identity, cinfo); }; if ((deserializer = cinfo.Deserializer) == null || (otherDeserializers = cinfo.OtherDeserializers) == null) { cacheDeserializers(); } Func mapIt = GenerateMapper( deserializer, otherDeserializers, map); if (mapIt != null) { while (reader.Read()) { TReturn next; try { next = mapIt(reader); } catch (DataException) { cacheDeserializers(); mapIt = GenerateMapper( deserializer, otherDeserializers, map); next = mapIt(reader); } yield return next; } } } finally { try { if (ownedReader != null) { ownedReader.Dispose(); } } finally { if (ownedCommand != null) { ownedCommand.Dispose(); } } } } private static Func GenerateMapper( Func deserializer, Func[] otherDeserializers, object map) { switch (otherDeserializers.Length) { case 1: return r => ((Func)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r)); case 2: return r => ((Func)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r)); case 3: return r => ((Func)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r)); #if !CSHARP30 case 4: return r => ((Func)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r)); #endif case 5: return r => ((Func)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r)); case 6: return r => ((Func)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r), (TSeventh)otherDeserializers[5](r)); case 7: return r => ((Func)map)( (TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r), (TSeventh)otherDeserializers[5](r), (TEighth)otherDeserializers[6](r)); case 8: return r => ((Func)map)( (TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r), (TSeventh)otherDeserializers[5](r), (TEighth)otherDeserializers[6](r), (TNinth)otherDeserializers[7](r)); case 9: return r => ((Func)map)( (TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r), (TSeventh)otherDeserializers[5](r), (TEighth)otherDeserializers[6](r), (TNinth)otherDeserializers[7](r), (TTenth)otherDeserializers[8](r)); default: throw new NotSupportedException(); } } #endregion } }