2011-09-01 82 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將自動將底層連接資源池化。

相關問題