我有以下方法:
public IEnumerable<Foo> GetFoo(int x, string y)
{
return from r in new GetFoo(x, y)
select new Foo
{
x = r.Get<int>("x"),
y = r.Get<string>("y"),
z = r.Get<DateTime?>("z"),
};
}
GetFoo
是一个包含存储过程并实现IEnumerable<DbDataReader>
的类。因此,r
是DbDataReader
。
我希望它执行查询语法的查询并返回List<Foo>
如果没有这样做,我的理解是调用者可能根本不迭代整个列表,然后数据库连接将不会被关闭。我知道我可以把它放在括号中并调用ToList()但我想尽可能避免这种情况。我们有200多个存储过程,开发人员很容易错过添加ToList()。
我能做些什么来实现我想要的东西吗?
更新
这不是linq to sql,我创建了一个实现GetFoo
的自定义类IEnumerable<DbDataReader>
。返回的IEnumerator<DbDataReader>
如下所示:
private class Enumerator : IEnumerator<DbDataReader> {
DbDataReader _;
public Enumerator(DbDataReader r) { _ = r; }
public DbDataReader Current { get { return _; } }
public void Dispose() { _.Dispose(); }
object System.Collections.IEnumerator.Current { get { return _; } }
public bool MoveNext() { return _.Read(); }
public void Reset() { throw new NotImplementedException(); }
}
更新2
我无法强制执行调用ToList()
和/或要求List<Foo>
成为此方法的返回类型,以及其他类似的方法。开发人员审核应该抓住不将其转换为列表。不幸的是,如果错过那里并在QA测试中,应用程序将运行良好。我只是想阻止数据库连接可以保持打开状态。
答案 0 :(得分:1)
Linq基于延迟加载。当您调用ToList时,它会执行命令。否则它不会执行它。所以你的问题的答案是否定的。但是,我不确定,也许代码合同可以帮助您标记方法,或者在返回List的函数中调用上面的代码。在这种情况下,开发人员将被绑定返回List。否则代码将无法编译。
答案 1 :(得分:0)
您需要更改返回类型以实现此目的。您可以将所有此类方法的返回类型更改为List<T>
,以便开发人员必须以其他方式调用ToList,编译器将抛出错误或返回IEnumerable<DbDataReader>
的方法应返回List<DbDataReader>
其中DbDataReader是在内存数据读取器中实现的自定义,它是通过读取实际读者的数据生成的,这样您就不必担心读者会被打开。
答案 2 :(得分:0)
返回
List<Foo>
显然,这不是你在做什么。您正在返回IEnumerable<Foo>
。如果您返回List<Foo>
,则开发人员无法致电ToList
。
如果你真的不想这样做,我会建议创建某种QueryObject
,它将包含你方法中的逻辑。然后通过某种辅助类调用它,它会在内部调用ToList
。这也符合DRY原则。
此外,您似乎只实现了对返回数据集的某种解析。所以你只需要实现这个解析:
public abstract class BaseStoredProcedureQuery<TReturn>
{
protected abstract TReturn ParseRecord(DbDataReader r);
protected IEnumerable<TReturn> ParseQuery(IEnumerable<DbDataReader> readers)
{
return readers.Select<DbDataReader,TReturn>(ParseRecord).ToList();
}
}
public class Query1 : BaseStoredProcedureQuery<Foo>
{
protected override Foo ParseRecord(DbDataReader r)
{
return new Foo
{
x = r.Get<int>("x"),
y = r.Get<string>("y"),
z = r.Get<DateTime?>("z"),
};
}
public IEnumerable<Foo> GetFoo(int x, string y)
{
return ParseQuery(GetFoo(x, y));
}
}