2011-09-01 80 views
0

我注意到我的网页上有一些奇怪的行为。我有一个WCF数据服务,提供JSON来填充jqGrid。该服务使用javascript/ajax调用。SqlCommand.ExecuteReader是否会自动打开数据库连接?

然后我有一些服务器端代码,也调用相同的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.'); 
       } 
      }); 
     } 

回答

3

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

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

问题是您的SqlReader会在使用时保持连接占用。您不能将连接用于其他任何事情(例如执行其他阅读器,甚至是其他语句)。在阅读器关闭之前,您的连接已基本锁定。

通常情况下,就像亚当说的那样,将你的陈述包装在一个使用块中,你的问题就会解决。但是,我注意到你似乎从某种类型的缓存(queryable.Provider)中获取连接。如果您试图重复使用连接或缓存它,则会遇到同样的问题。

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

相关问题