产生返回和方法状态
本文关键字:方法 状态 返回 | 更新日期: 2023-09-27 18:17:23
我试图从我的数据库执行方法中删除一些重复。我有以下结构的一堆方法:
IDbConnection connection = mConnections[pConnectionID];
bool wasAlreadyOpen = connection.State == ConnectionState.Open;
try
{
if (!wasAlreadyOpen)
connection.Open();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = pSQL;
if (pParams != null)
ApplyParameters(pParams, command);
// do something interesting with command
}
}
finally
{
if (!wasAlreadyOpen)
connection.Close();
}
我将这个逻辑提取到另一个签名为
的方法中:private object ExecuteQuery(int pConnectionID, string pSQL,
Func<IDbCommand, object> pQuery, IEnumerable<QueryParameter> pParams)
,在算法的// do something
部分,这样做:
return pQuery(command);
这似乎工作得很好,除了一个问题。在我的ExecuteReader
方法中,查询代码如下:
using (IDataReader reader = command.ExecuteReader())
if (reader != null)
while (reader.Read())
yield return reader;
问题似乎是,为yield return
保存的"状态"延迟执行仅取自包含yield
语句的方法。如果我将上面的四行提取到它自己的方法或匿名方法/lambda中,那么在读取数据时就没有足够的状态来保持数据库连接打开。
是否有一种方法来提取这个逻辑的方式,我这样做,或者我只剩下内联这个特定的方法,忽略重复?
我的解决方案是不从数据库惰性加载。我有一种感觉,无论如何,从数据库惰性加载不是一个好主意。相反,我在ExecuteReader方法中添加了一个转换函数Func<IDataRecord, T>
参数。读取的数据记录然后立即转换为对象,而不是期望调用者获取IEnumerable<IDataRecord>
并对其进行处理。
我喜欢yield return
版本的简洁,但我认为最终最好不要从DB加载。
一次又一次地返回相同的reader副本有什么意义呢?
<<p> 错误的逻辑/strong>using (IDataReader reader = command.ExecuteReader())
if (reader != null)
while (reader.Read())
yield return reader;
你所做的是多次返回相同的DataReader对象。
你需要做的是从reader对象创建类对象并返回读取的数据。
伪代码
using (IDataReader reader = command.ExecuteReader())
if (reader != null)
while (reader.Read())
{
MyObject obj = new MyObject(reader.getInt32(0), reader.getString(1), reader.getFloat(2));
yield return obj;
}
首先,我认为你应该使你的方法泛型。也就是说,你的方法不应该返回object
,它应该返回T
:
private T ExecuteQuery<T>(int pConnectionID, string pSQL,
Func<IDbCommand, T> pQuery, IEnumerable<QueryParameter> pParams)
现在,我认为你应该做的是为集合添加另一个ExecuteQuery
重载:
private IEnumerable<T> ExecuteQuery<T>(int pConnectionID, string pSQL,
Func<IDbCommand, IEnumerable<T>> pQuery, IEnumerable<QueryParameter> pParams)
将使用yield return
本身实现。比如:
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = pSQL;
if (pParams != null)
ApplyParameters(pParams, command);
foreach (var x in pQuery(command))
yield return x;
}
这样,该命令将只在结果的迭代完成后才被处理(或者如果它过早终止)。
(我不完全确定这一点,但有可能重载解析将为集合选择错误的重载。在这种情况下,将集合版本重命名为ExecuteQueryCollection
。)