Похоже на то, что я выложил здесь
public IEnumerable<S> Get<S>(string query, Action<IDbCommand> parameterizer,
Func<IDataRecord, S> selector)
{
using (var conn = new T()) //your connection object
{
using (var cmd = conn.CreateCommand())
{
if (parameterizer != null)
parameterizer(cmd);
cmd.CommandText = query;
cmd.Connection.ConnectionString = _connectionString;
cmd.Connection.Open();
using (var r = cmd.ExecuteReader())
while (r.Read())
yield return selector(r);
}
}
}
У меня есть эти простые методы расширения для облегчения вызова:
public static void Parameterize(this IDbCommand command, string name, object value)
{
var parameter = command.CreateParameter();
parameter.ParameterName = name;
parameter.Value = value;
command.Parameters.Add(parameter);
}
public static T To<T>(this IDataRecord dr, int index, T defaultValue = default(T),
Func<object, T> converter = null)
{
return dr[index].To<T>(defaultValue, converter);
}
static T To<T>(this object obj, T defaultValue, Func<object, T> converter)
{
if (obj.IsNull())
return defaultValue;
return converter == null ? (T)obj : converter(obj);
}
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null || obj == DBNull.Value;
}
Так что теперь я могу позвонить:
var query = Get(sql, cmd =>
{
cmd.Parameterize("saved", 1);
cmd.Parameterize("name", "abel");
}, r => new User(r.To<int>(0), r.To<string>(1), r.To<DateTime?>(2), r.To<bool>(3)));
foreach (var user in query)
{
}
Это полностью универсально, подходит для любой модели, которая соответствует интерфейсам ado.net. Объект подключения и считыватель удаляются только после однократного перечисления коллекции.