SqlCommand.ExecuteReader从未自动打开数据库连接

本文关键字:数据库连接 ExecuteReader SqlCommand | 更新日期: 2023-09-27 18:07:20

我注意到我的网页上有一些奇怪的行为。我有一个WCF数据服务,它提供JSON来填充jqGrid。该服务是使用javascript/ajax调用的。

然后我有一些服务器端代码,也调用相同的WCF服务来获取数据。

在我的WCF服务中,我运行cmd.ExecuteReader()而没有事先打开连接,并且在某些情况下它不会抱怨连接-似乎是当我从javascript调用数据服务时。然而,当我从代码后端(即服务器端)调用服务时,我得到的错误是"ExecuteReader需要一个开放的可用连接"。

有人知道这个问题吗?我已经尽可能地缩小范围了。似乎唯一的区别是我是从客户端还是从服务器端调用服务。下面是我的代码:

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class JsonService
{
    static String _connection = ConfigMgr.ConnectionStrings["MyConnStr"];
    static DomainEntities dbContext = new DomainEntities(_connection);
    [OperationContract]
    [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest,
                         RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    public JsonGrid Get()
    {
        return new JsonGridContract(dbContext.Products.ToJson()); 
    }
}

下面是调用ExecuteReader()的地方。它拦截提供程序,将表达式树转换为SQL,然后执行它,将结果解析为基于字符串的JSON,而不是域对象。

    public static List<JsonRow> ToJson(this IQueryable queryable)
    {
        Expression expression = queryable.Expression;
        expression = Evaluator.PartialEval(expression);
        if !(queryable.Provider is JsonQueryProvider)
              throw new InvalidOperationException("Provider is invalid");
        String table = (queryable.Provider as JsonQueryProvider).Table; 
        SqlConnection connection = (queryable.Provider as JsonQueryProvider).Connection; 
        Type elementType = TypeSystem.GetElementType(expression.Type);
        TranslateResult result = new QueryTranslator(table).Translate(expression);
        SqlCommand cmd = connection.CreateCommand();
        cmd.CommandText = result.CommandText;
        SqlDataReader reader = cmd.ExecuteReader();
        List<JsonRow> jsonResult = new List<JsonRow>(); 
        while (reader.Read())
            {
                JsonRow instance = new JsonRow(reader.FieldCount); 
                for (int i = 0, n = reader.FieldCount; i < n; i++)
                {
                    var items = instance.Items; 
                    if (reader.IsDBNull(i))
                    {
                        items[i] = string.Empty;  
                    }
                    else
                    {
                        items[i] = reader[i].ToString(); 
                    }
                }
                jsonResult.Add(instance); 
            }
        reader.Close(); 
        return jsonResult; 
    }

如前所述,即使我从未打开连接,该方法也可以正常执行。我使用AJAX客户端,

  $.ajax(
            {
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "Services/JsonService.svc/Get",
                data: {},
                dataType: "json",
                success: function (data, textStatus) {
                    if (textStatus == "success") {
                        var thegrid = $("#jqGrid")[0];
                        thegrid.addJSONData(data.d);
                    }
                },
                error: function (data, textStatus) {
                    alert('An error has occured retrieving data.');
                }
            });
        }

SqlCommand.ExecuteReader从未自动打开数据库连接

首先要排除的是不处置任何对象。您的SqlCommand, SqlConnection和SqlDataReader都应该使用stmt块。那么就不需要显式关闭了。看看这是否会全面失败。我很好奇,如果只是垃圾收集器还没有收集到杀死你的连接对象。

using(SqlConnection connection = new SqlConnection(...))
{
...
}

问题是,您的SqlReader将保持占用连接,而它是在使用。您不能将该连接用于其他任何事情(例如执行另一个读取器,甚至是另一条语句)。在reader关闭之前,您的连接基本上处于锁定状态。

通常,就像Adam说的,把你的语句包装在using块中,你的问题就解决了。但是,我注意到您似乎正在从某种缓存(queryable.Provider)中抓取连接。如果您试图重复使用您的连接,或缓存它,您将遇到同样的问题。

如果您想利用ADO。. NET的连接池功能,您需要在您的using块中创建一个新的connection实例,并且只重用完全相同的连接字符串。ADO。. NET将自动池化底层连接资源。