using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RDH.Data { public class GridReader : IDisposable { private IDataReader reader; private IDbCommand command; private Identity identity; internal GridReader(IDbCommand command, IDataReader reader, Identity identity) { this.command = command; this.reader = reader; this.identity = identity; } /// /// Read the next grid of results /// public IEnumerable Read() { if (reader == null) throw new ObjectDisposedException(GetType().Name); if (consumed) throw new InvalidOperationException("Each grid can only be iterated once"); var typedIdentity = identity.ForGrid(typeof(T), gridIndex); CacheInfo cache = SqlMapper.GetCacheInfo(typedIdentity); var deserializer = cache.Deserializer; Func> deserializerGenerator = () => { deserializer = SqlMapper.GetDeserializer(typeof(T), reader, 0, -1, false); cache.Deserializer = deserializer; return deserializer; }; if (deserializer == null) { deserializer = deserializerGenerator(); } consumed = true; return ReadDeferred(gridIndex, deserializer, typedIdentity, deserializerGenerator); } private IEnumerable MultiReadInternal(object func, string splitOn) { var identity = this.identity.ForGrid(typeof(TReturn), new Type[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }, gridIndex); try { foreach (var r in SqlMapper.MultiMapImpl(null, null, func, null, null, splitOn, null, null, reader, identity)) { yield return r; } } finally { NextResult(); } } #if CSHARP30 public IEnumerable Read(Func func, string splitOn) #else public IEnumerable Read(Func func, string splitOn = "id") #endif { return MultiReadInternal(func, splitOn); } #if CSHARP30 public IEnumerable Read(Func func, string splitOn) #else public IEnumerable Read(Func func, string splitOn = "id") #endif { return MultiReadInternal(func, splitOn); } #if CSHARP30 public IEnumerable Read(Func func, string splitOn) #else public IEnumerable Read(Func func, string splitOn = "id") #endif { return MultiReadInternal(func, splitOn); } #if CSHARP30 public IEnumerable Read(Func func, string splitOn) #else public IEnumerable Read(Func func, string splitOn = "id") #endif { return MultiReadInternal(func, splitOn); } #if CSHARP30 public IEnumerable Read(Func func, string splitOn) #else public IEnumerable Read(Func func, string splitOn = "id") #endif { return MultiReadInternal(func, splitOn); } #if !CSHARP30 public IEnumerable Read(Func func, string splitOn = "id") { return MultiReadInternal(func, splitOn); } #endif private IEnumerable ReadDeferred(int index, Func deserializer, Identity typedIdentity, Func> deserializerGenerator) { try { while (index == gridIndex && reader.Read()) { object next; try { next = deserializer(reader); } catch (DataException) { deserializer = deserializerGenerator(); next = deserializer(reader); } yield return (T)next; } } finally // finally so that First etc progresses things even when multiple rows { if (index == gridIndex) { NextResult(); } } } private int gridIndex; private bool consumed; private void NextResult() { if (reader.NextResult()) { gridIndex++; consumed = false; } else { Dispose(); } } public void Dispose() { if (reader != null) { reader.Dispose(); reader = null; } if (command != null) { command.Dispose(); command = null; } } } }