无法访问已处置的对象
对象名称:' OracleConnection'。
以下是代码:
public class MyController : Controller
{
readonly IDbConnection sqlConn = new OracleConnection(ConfigurationManager.ConnectionStrings["LogDbContext"].ConnectionString);
readonly string selectLog = "select * from LOG";
readonly string insertLog = "insert into LOG (ID, Address) values (:ID, :Address)";
// GET: Log
public ActionResult Index()
{
using (sqlConn)
{
sqlConn.Open();
//IEnumerable log = sqlConn.Query(selectLog);
IEnumerable<Log> log = sqlConn.Query<Log>(selectLog);
foreach (var item in log)
{
Console.WriteLine(item.ToString());
}
}
return View();
}
public ActionResult Create()
{
using (sqlConn)
{
sqlConn.Open();
var log = new Log()
{
ID = 1,
Address = "test"
};
sqlConn.Execute(insertLog, log);
}
return View();
}
}
似乎放置&#34; sqlConn&#34;进入using语句使其自动处理,所以当函数再次运行时,它无法处理连接。
我该怎样防止这种情况?我不希望每次需要时都手动打开和关闭连接。
更新
使用以下答案提供的所有帮助(一切正确)我最后使用类的构造函数在每次必须使用类时实例化一个新连接。
//removed the wrong static attribute and the instantiation
readonly IDbConnection sqlConn;
readonly string selectLog = "select * from LOG";
readonly string insertLog = "insert into LOG (ID, Address) values (:ID, :Address)";
// Created a constructor to instantiate the connection everytime the controller gets called
public LogController()
{
sqlConn = new OracleConnection(ConfigurationManager.ConnectionStrings["LogDbContext"].ConnectionString);
}
答案 0 :(得分:7)
似乎将“sqlConn”放入using语句会使其自动处理
是的,这就是using
声明的用途。
我该怎样防止这种情况?我不希望每次需要时都手动打开和关闭连接。
我强烈建议您每次需要时执行打开和关闭连接 - 但是为它使用局部变量,而不是字段。这样每个操作都会获得一个单独的逻辑连接,因此您不必担心线程问题等。让连接池负责提高效率。我怀疑你担心在每次调用时打开一个“物理”连接(建立一个新的TCP / IP连接或其他) - 但连接池是为了确保不会发生超过它所需要的。
只需在方法中创建一个新连接:
using (var connection = new OracleConnection(...))
{
...
}
...和衡量表现以确定它是否令人满意。不要开始猜测你是否会遇到问题(并采用导致比他们解决的更多问题的不良解决方法)。
作为使用new
的替代方法,控制器构造函数可以接受连接提供程序并要求新连接,但从根本上说它是关于每次创建新的一次性连接。
如果由于某种原因你真的,真的不想处理连接,只需删除using
语句 - 但非常意识到你需要处理并发你自己。你几乎肯定不想这样做。
答案 1 :(得分:6)
您已将sqlConn
声明为static readonly
,这意味着整个应用程序只有一个实例。将其包含在using()
中意味着在第一个请求完成后,sqlConn
将被处理掉,后续请求将失败并显示ObjectDisposedException
。
要解决此问题,请按以下步骤重写代码:
var connectionString =
ConfigurationManager.ConnectionStrings["LogDbContext"].ConnectionString;
using(var sqlConn = new OracleConnection(connectionString))
{
// ...
}
现在,至于你不想每次打开连接,这就是你必须要做的。连接很珍贵,必须小心管理:尽可能晚开,一旦你不再需要就关闭。您始终可以将连接初始化逻辑分解为单独的方法,或者采用Enterprise(r)(tm)方式并将其注入。
答案 2 :(得分:2)
这正是using
的目的。一旦退出使用块,它就会处理IDisposable对象。
https://msdn.microsoft.com/en-us/library/yh598w02.aspx
这是SQL连接的好习惯 - 连接池确保打开新连接没有明显延迟,因为数据库层在池中保留了一个或多个就绪。
我会修改你的代码如下:
public class MyController : Controller
{
static readonly string connStr = ConfigurationManager.ConnectionStrings["LogDbContext"].ConnectionString;
readonly string selectLog = "select * from LOG";
readonly string insertLog = "insert into LOG (ID, Address) values (:ID, :Address)";
// GET: Log
public ActionResult Index()
{
using (var sqlConn = new OracleConnection(connStr))
{
sqlConn.Open();
//IEnumerable log = sqlConn.Query(selectLog);
IEnumerable<Log> log = sqlConn.Query<Log>(selectLog);
foreach (var item in log)
{
Console.WriteLine(item.ToString());
}
}
return View();
}
public ActionResult Create()
{
using (var sqlConn = new OracleConnection(connStr))
{
sqlConn.Open();
var log = new Log()
{
ID = 1,
Address = "test"
};
sqlConn.Execute(insertLog, log);
}
return View();
}
}
答案 3 :(得分:0)
使用本地连接 (在方法中),这是首选的实施方式
public class MyController : Controller {
// No sqlConn field
public ActionResult Index() {
using (IDbConnection sqlConn = new OracleConnection(...)) {
sqlConn.Open();
...
}
}
或者让对象的实例,而不是方法处理它,在这种情况下,你必须处理对象,从而检查你的代码:
public class MyController : Controller, IDisposable { // note IDisposable
// no static
readonly IDbConnection sqlConn = new OracleConnection(...);
public ActionResult Index() {
// No using
sqlConn.Open();
...
}
protected void Dispose(Boolean disposing) {
if (disposing) {
sqlConn.Dispose();
}
}
public Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
}
或者让 class 本身处理连接,最糟糕的,恕我直言,方式:
public class MyController : Controller {
static readonly IDbConnection sqlConn = new OracleConnection(...);
public ActionResult Index() {
// No using
sqlConn.Open();
...
}
private static void OnExit(Object sender, EventArgs e) {
sqlConn.Dispose();
}
static MyController() {
Application.ApplicationExit += OnExit;
}
}
无论你选择哪种方法,都不要混合这三个模型(你当前的代码是第一个和第三个实现的混合)。