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;
}
}
}
}