Por que meu SqlCommand devolver uma cadeia, quando deveria ser um int?

votos
4

Eu tenho uma consulta que deve sempre estar retornando um único int. Eu já registrada-lo a devolver uma cadeia totalmente alheios ao que deveria ser.

Estamos recebendo algumas FormatExceptions aleatórios que temos rastreados para baixo para várias consultas de banco de dados. Depois de algum log adicional, descobri que, esta manhã, a consulta a seguir voltou a string gladiador. Website.PkID é uma coluna int e trabalha a maior parte do tempo, mas algumas vezes ele falha miseravelmente e retorna quer um int que é waaaay lá fora (maior do que qualquer WebsiteID válido) ou uma seqüência aleatória.

Esta consulta particular é atingido uma vez por início de sessão. Não está usando uma conexão compartilhada, por isso estou tendo dificuldade para entender como ele poderia obter um resultado tão confusa. Poderia haver algum tipo de corrupção nos pools de conexão?

Eu não acho que o problema é isolado para esta consulta. Eu vi FormatExceptions semelhantes (por causa de um resultado inesperado) provenientes de consultas LINQ também. Nós também descoberto alguns destes erros em torno do mesmo tempo:

Um erro de nível de transporte ocorreu ao enviar o pedido para o servidor. (Provedor: TCP Provider, erro: 0 - uma conexão existente forçosamente foi fechada pelo host remoto.

Poderia ser um problema de conexão? Ou talvez nós estamos começando conjuntos de resultados misturados entre o servidor db eo servidor web? Isto realmente me coçar a cabeça.

consulta agressor:

public static int GetActiveWebSiteID(string storeID, string statusID)
{
    int retval;

    string sql = @SELECT isnull(MAX(PkID),0) FROM WebSite 
                   WHERE StoreID = @StoreID 
                   AND WebSiteStatusID = @WebSiteStatusID;

    SqlConnection conn = new SqlConnection(Settings.ConnString);
    SqlCommand cmd = new SqlCommand(sql, conn);
    cmd.CommandType = CommandType.Text;
    cmd.Parameters.AddWithValue(@StoreID, (object)storeID ?? DBNull.Value);
    cmd.Parameters.AddWithValue(@WebSiteStatusID, (object)statusID ?? DBNull.Value);

    conn.Open();
    using(conn)
    {
        var scalar = cmd.ExecuteScalar(); // <-- This value returned here should only ever be an int, but randomly is a string

        retval = Convert.ToInt32(scalar);
    }
    return retval;
}

A consulta acima tem trabalhado muito bem durante anos até recentemente. Agora temos um monte de consultas LINQ adicionais no aplicativo (não tenho certeza se isso faz uma diferença). Nós estamos correndo .Net 3.5.

Publicado 19/05/2009 em 14:33
fonte usuário
Em outras línguas...                            


9 respostas

votos
9

Depois de alguns meses de ignorar esta questão, começou a atingir uma massa crítica como o tráfego aumentou gradualmente. Nós aumentamos o registo e encontraram numerosos casos definitivos, onde, sob carga pesada, completamente diferentes conjuntos de resultados que se voltaram para consultas relacionadas.

Nós assistimos as consultas em Profiler e foram capazes de ver que os maus resultados foram sempre associado com o mesmo SPID, e que cada mau resultado era sempre uma consulta por trás da instrução SQL real que está sendo consultado. Era como um conjunto de resultados foi perdido e conjunto de tudo o resultado foi o próximo na SPID (a partir de outra ligação na mesma piscina) foi devolvido. Louco.

Por tentativa e erro, nós finalmente rastreou um punhado de consultas SqlCommand ou LINQ cujos SqlConnection não foi fechada imediatamente após o uso. Em vez disso, através de uma programação superficial proveniente de um erro de conexões LINQ, os objectos DataContext foram eliminados (e ligações fechadas) apenas no final de um pedido, em vez de imediatamente.

Uma vez que refactored estes métodos para fechar imediatamente a conexão com um C # "usando" bloco (liberando que piscina para a próxima solicitação), recebemos há mais erros. Enquanto nós ainda não sabemos a razão subjacente a um pool de conexão iria ficar tão misturado, fomos capazes de deixar todos os erros deste tipo. Este problema foi resolvido em conjunto com outro erro semelhante que eu postei, encontrada aqui: O que causa a "conexão interna Erros fatais"?

Respondeu 22/09/2009 em 19:18
fonte usuário

votos
1

Eu vi recentemente um caso em que o código foi alternando seqüências de conexão inesperadamente. Para fins de diagnóstico, agradar código rígido a seqüência de conexão e ver se o problema desaparece.

Além disso, por causa de sanidade, por favor use aninhados usando blocos como:

using(SqlConnection conn = new SqlConnection("hard-coded connection string"))
{
    using (SqlCommand cmd = new SqlCommand(sql, conn))
    {
        // more init
        object scalar = cmd.ExecuteScalar();

        // process result
    }
 }

Não seria surpresa para mim descobrir que há duas instâncias de banco de dados, e em um, PKID é um int, em outro é varchar.


Dê uma olhada com o SQL Profiler para ver se você pode pegar o retorno do "gladiador". No outro caso, eu estava trabalhando com, SQL Profiler mostrou nada, o que indica que a consulta real estava indo para um banco de dados diferente.

Respondeu 19/05/2009 em 18:09
fonte usuário

votos
1

Eu acho que você estava pensando sqlCommand.ExecuteNonQueryque retorna o número de linhas afetadas dentro de um valor de int ...

Esta é a definição do método ExecuteScalar:

public override object ExecuteScalar()
Member of System.Data.SqlClient.SqlCommand

Resumo:

Executa a consulta e retorna a primeira coluna da primeira linha no conjunto de resultados retornado pela consulta. Colunas ou linhas adicionais são ignorados.

retorna:

A primeira coluna da primeira linha no conjunto de resultados, ou uma referência nula (Nada no Visual Basic) se o conjunto de resultados está vazio.

Então, eu acho que a maneira comum de devolver essa coluna é como uma representação de string do valor da coluna.

Respondeu 19/05/2009 em 15:25
fonte usuário

votos
1

Tipo de retorno da função de ExecuteScalar () é object, e você declarar a variável de resultado com a varpalavra-chave. Isso não é realmente uma boa combinação, porque você está colocando muita pressão sobre o sistema para obter o tipo de inferência direita.

Respondeu 19/05/2009 em 14:58
fonte usuário

votos
0

Estou assumindo que Settings.ConnString é lido a partir Web.Config ou o registro e é reutilizado outras rotinas estáticos. Poderia ser possível que haja um problema de tempo em que um segundo método é executado antes da chamada para cmd.ExecuteScalar () em sua rotina que modifica cmd.CommandText na conexão?

Espero que isto ajude,

Conta

Respondeu 20/05/2009 em 17:45
fonte usuário

votos
0

Eu acho que nem a sua consulta postou nem LINQ são o problema.

Tem a certeza de que você está olhando para a fonte certa? Como é o método chamado? Como está registrando feito?

Selecionar não está quebrado.

Respondeu 19/05/2009 em 18:12
fonte usuário

votos
0

Existe alguma semelhança de quando ele falhar para retornar um int?

Desde sua consulta sempre apenas retorna uma única coluna em uma única linha, o que você ganha se você usar um mais typesafe ExecuteReader e tomar o valor do primeiro coluna?

É sempre retornando uma linha? Se a WHEREcláusula faz com que ele retornar nenhum registro (dizem os parâmetros não são o que você pensa que são), o seu ISNULLnão entrar em vigor - não há filas em tudo, e ExecuteScalar deve retornar um NULL.

Respondeu 19/05/2009 em 17:59
fonte usuário

votos
0

Poderia haver mais de uma tabela WebSite. você pode qualificar-se à mesa com nome de esquema:

isnull SELECIONAR (MAX (PKID), 0) FROM YourSchema.WebSite ONDE StoreID = @StoreID E WebSiteStatusID = @WebSiteStatusID

Respondeu 19/05/2009 em 16:56
fonte usuário

votos
0

o campo "PKID" é um VARCHAR / char na Tabela "Site".

Se a parte "ISNULL" da consulta é verdade, então ele irá retornar um inteiro (0), então ele irá retornar uma string com o valor de "PKID"

Respondeu 19/05/2009 em 15:46
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more