我试图从我的数据库执行方法中删除一些重复。我有一堆具有以下结构的方法:
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,那么就没有足够的状态来在读取数据时保持数据库连接打开。
有没有办法按照我这样做的方式提取这个逻辑,或者我只留下内联这个特定方法并忽略重复?
答案 0 :(得分:1)
我的解决方案是不要懒惰地从数据库加载。我觉得从懒惰地加载数据库并不是一个好主意。相反,我已向ExecuteReader方法添加了转换函数Func<IDataRecord, T>
参数。然后,读取的数据记录会立即转换为对象,而不是期望调用者使用IEnumerable<IDataRecord>
并对其执行某些操作。
我喜欢yield return
版本的简洁,但我认为最好不要懒散地加载数据库。
答案 1 :(得分:1)
一次又一次地返回同一份阅读器有什么意义?
错误的逻辑
using (IDataReader reader = command.ExecuteReader())
if (reader != null)
while (reader.Read())
yield return reader;
您正在做的是多次返回相同的DataReader对象。
伪代码
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;
}
答案 2 :(得分:0)
首先,我认为你应该让你的方法通用。也就是说,您的方法不应该返回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
。)