SqlCommand.ExecuteReader когда-нибудь автоматически открывает соединение БД? - PullRequest
0 голосов
/ 01 сентября 2011

Я замечаю странное поведение на моей веб-странице.У меня есть служба данных 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.');
                }
            });
        }

Ответы [ 2 ]

3 голосов
/ 01 сентября 2011

Первое, что нужно исключить, это то, что вы не утилизируете ни один из своих объектов.Ваш SqlCommand, SqlConnection и SqlDataReader должны использовать блоки stmt.Вам не нужно ваше явное закрытие тогда.Посмотрим, не удастся ли это тогда по всем направлениям.Мне любопытно, что сборщик мусора еще не собрал, чтобы убить ваш объект подключения.

using(SqlConnection connection = new SqlConnection(...))
{
...
}
0 голосов
/ 02 сентября 2011

Проблема в том, что ваш SqlReader будет держать соединение занятым, пока он используется. Вы не можете использовать соединение для чего-либо еще (например, выполнение другого читателя или даже другого оператора). Пока устройство чтения не закрыто, ваше соединение по существу заблокировано.

Как правило, как говорит Адам, заключите ваши утверждения в блок использования, и ваша проблема будет решена. Тем не менее, я заметил, что вы, похоже, захватываете ваше соединение из какого-то кеша (queryable.Provider). Если вы пытаетесь использовать ваше соединение повторно или кэшируете его, вы столкнетесь с той же проблемой.

Если вы хотите воспользоваться возможностями пула подключений ADO.NET, вам нужно создать новый экземпляр Connection внутри вашего блока using и только повторно использовать EXACT ту же строку подключения. ADO.NET автоматически объединит базовые ресурсы соединения.

...