我有两个问题。
1)您是否应始终在连接上使用using语句?那么,我会在连接上使用它,然后在连接中的读者上使用另一个?所以我将使用两个使用语句。
2)假设您在连接上使用using语句,并且还在连接上使用了读取器。所以你有两个使用语句。它会创建两个Try {} Finally {}块还是只创建一个?
谢谢!
答案 0 :(得分:7)
这里要小心。您应始终在任何实现IDisposable的本地对象上使用using语句。这不仅包括连接和读者,还包括命令。但有时候使用语句 where 可能会很棘手。如果你不小心它可能会导致问题。例如,在使用语句之后的代码中,在您开始使用它之前将关闭您的阅读器:
DataReader MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
return rdr;
}
}
}
相反,您有四种选择。一种是等到创建使用块,直到你调用函数:
DataReader MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
return cmd.ExecuteReader();
}
}
using (var rdr = MyQuery())
{
while (rdr.Read())
{
//...
}
}
当然,你仍然需要小心你的连接,这意味着记得在你使用该功能的任何地方写一个使用块。
选项二只是处理方法本身的查询结果,但会破坏数据层与程序其余部分的分离。第三个选项是让你的MyQuery()函数接受一个Action类型的参数,你可以在while(rdr.Read())循环中调用它,但这只是尴尬。
我通常更喜欢选项四:将数据读取器转换为IEnumerable,如下所示:
IEnumerable<IDataRecord> MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
现在所有内容都将正确关闭,处理它的代码都在一个地方。您还可以获得一个很好的奖励:您的查询结果将适用于任何linq运算符。
最后,我正在玩的新内容,以便下次我构建一个将IEnumerable与传递委托参数相结合的全新项目:
//part of the data layer
private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
{
//DL.ConnectionString is a private static property in the data layer
// depending on the project needs, it can be implementing to read from a config file or elsewhere
using (var cn = new SqlConnection(DL.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
addParameters(cmd.Parameters);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
然后我将在数据层中使用它,如下所示:
public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
{
//I could easily use a stored procedure name instead, and provide overloads for commandtypes.
return Retrieve(
"SELECT c.*
FROM [ParentTable] p
INNER JOIN [ChildTable] c ON c.ParentID = f.ID
WHERE f.ID= @ParentID", p =>
{
p.Add("@ParentID", SqlDbType.Int).Value = ParentID;
}
);
}
答案 1 :(得分:5)
1)你应该总是使用 关于连接的声明?所以,我愿意 在连接上使用它然后 另一个在读者内部 连接?所以我会用两个 使用陈述。
是的,因为他们实施了IDisposable
。并且不要忘记命令上的using
语句:
using (DbConnection connection = GetConnection())
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT FOO, BAR FROM BAZ";
connection.Open();
using (DbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
....
}
}
}
2)让我们说你使用了 关于连接的声明以及a 读者被退回了 连接。所以你有两个使用 声明。它创造了两个 尝试{}最后{}阻止或只阻止一个?
每个using
语句都会创建自己的try/finally
块
答案 2 :(得分:4)
当对象实现using
时,您应始终使用IDisposable
语句。这包括连接。
它将创建两个嵌套的try{}finally{}
块。
答案 3 :(得分:2)
特别要点1)。在asynchronous ADO.NET methods中使用连接时,你需要专门避免这种技术 - 比如BeginExecuteReader,因为很可能,你会超出范围并尝试在异步操作时处理连接仍在进行中。这类似于使用类变量而非局部变量的情况。通常,连接引用存储在用作异步操作的“控制块”的类中。
答案 4 :(得分:1)
回答每一个:
1)是的,这是最好的做法,尽快处置。
2)using()
将创建两个块,以相同的顺序彼此包装。它将首先处理内部对象(读取器),然后使用(连接)从外部处置对象。
答案 5 :(得分:0)