【问题标题】:Query statement works in SQL Server but it's not working in C#查询语句在 SQL Server 中有效,但在 C# 中无效
【发布时间】:2020-05-29 15:00:11
【问题描述】:

我有这个问题。

SELECT DISTINCT 
    nome as Nome, Cognome As Cognome, DataConsegna as Data, 
    'RichiesteAttrezzatura' [Tipo Richiesta] 
FROM 
    RichiesteAttrezzatura 

UNION 

SELECT DISTINCT 
    nome AS Nome, Cognome as Cognome, DataConsegna as Data, 
    'RichiesteMateriali' [Tipo Richiesta] 
FROM 
    RichiesteMateriali 

UNION 

SELECT DISTINCT 
    nome AS Nome, Cognome as Cognome, giorno AS Data, 
    'RichiesteVestiario' [Tipo Richiesta] 
FROM 
    RichiesteVestiario

如标题所示,问题是当我执行它时它在 SQL Server 中工作,但是当我在 C# 中尝试时它只返回一个空表。

根据我在网上和这个论坛上的理解,问题出在单引号上。

这是我的功能

adonet db;

DataProvider()
{ 
    db = new adonet();
    db.CreaConnessione();
}

public DataTable getRichiesteForDGV(int id)
{
    DataTable dt = new DataTable();

    string richiesteVestiario = "RichiesteVestiario";
    string richiesteMateriali = "RichiesteMateriali";
    string richiesteAttrezzatura = "RichiesteAttrezzatura";

    string sql = "SELECT DISTINCT nome as Nome, Cognome As Cognome, DataConsegna as Data, '" + richiesteAttrezzatura + "' [Tipo Richiesta] FROM RichiesteAttrezzatura " +
                "UNION SELECT DISTINCT nome AS Nome, Cognome as Cognome, DataConsegna as Data, '" + richiesteMateriali + "' [Tipo Richiesta] FROM RichiesteMateriali " +
                "UNION SELECT DISTINCT nome AS Nome, Cognome as Cognome, giorno AS Data, '" + richiesteVestiario + "' [Tipo Richiesta] FROM RichiesteVestiario";

    db.EseguiQueryWithParams(sql, new SqlParameter("@id", id));

    return dt;
}

public DataTable EseguiQueryWithParams(string sql, params SqlParameter[] parameters)
    {
        ApriConnessione();
        string nometab = "dump";
        cmd.CommandText = sql;

        cmd.CommandType = System.Data.CommandType.Text;
        cmd.Parameters.AddRange(parameters);
        try
        {
            adp = new SqlDataAdapter(cmd);
            if (dset.Tables[nometab] != null)
                dset.Tables[nometab].Clear();

            adp.Fill(dset, nometab);
            DataTable d = dset.Tables[nometab];
            //d.Columns;
            return d;
        }
        catch (Exception e)
        {
            throw e;
            //throw new System.Exception("Errore nella lettura della tabella");

        }
        finally
        {
            adp.Dispose();
            cmd.Dispose();
            ChiudiConnessione();
        }

    }

感谢任何帮助。我已经更新了帖子,因为我知道问题出在我的 C# 上

【问题讨论】:

  • 你的代码在哪里?
  • SQL Server 不会关心查询是在 C# 中还是在 SQL Server Management Studio 中执行的。第一个查询应该在任何地方都可以工作,如果没有,那么问题不在 SQL Server 部分,而是在 C# 部分。向我们展示用于执行它的 C# 代码。第二个查询 OTOH 不是有效的 SQL。 PS:顺便说一句,你可以去掉 DISTINCT,因为 UNION 总是删除重复的,否则你应该使用 UNION ALL。
  • 为什么要在 SQL 语句中注入值? 参数.
  • 您将忽略 EseguiQueryWithParams 的结果并返回您在 getRichiesteForDGV 开始时创建的(空)数据表
  • “感谢任何帮助。” - 学习调试。获取实际发送的 SQL 字符串。看看这是否适用于 SSMS。哦,也许——只是也许——告诉我们这个错误。

标签: c# asp.net sql-server


【解决方案1】:

首先,我要花一点时间建议对 EseguiQueryWithParams() 进行一些更改,这些更改太大而无法作为评论。

对于初学者来说,它处理连接的方式is not good practice. 阅读链接,直到你理解为止。相反,您需要一个通用方法或属性来告诉您连接字符串,仅此而已。对方法的其他更改在代码中应该都可以理解:

private DataTable EseguiQuery(string sql, params SqlParameter[] parameters)
{
    // The method should only supply the string. 
    // DO NOT TRY TO REUSE THE SAME CONNECTION OBJECT!
    string connectionString = Connessione();
    var dset = new DataSet(); //creating a new dataset for this query also means there's no need to check and clear it further down

    //Using blocks guarantee the items are disposed, even if an exception is thrown
    using (var connection = new SqlConnection(connectionString))
    using (var cmd = new SqlCommand(sql, connection))
    using (var adp = new SqlDataAdapater(cmd))
    {
        cmd.CommandText = sql; //cmd.CommandType already has "Text" as the default value
        if (parameters is object && parameters.Length > 0)
        {   //conditional test lets us skip the parameters argument when calling the method
            cmd.Parameters.AddRange(parameters);
        }
        adp.Fill(dset); // Fill() opens and closes the connection automatically
        return dset.Tables[0]; 
    }
} // No try/catch anywhere, because the old try/catch didn't do anything

看看它的代码少了多少(17 行对 31 行,清理 cmets 之后),但它完成了所有相同的事情。甚至打开和关闭连接都被覆盖了,即使在哪里也不太明显。此外,它还允许您跳过传递参数,如下所示:

var result = db.EseguiQuery(sql)

另一个重要的变化是使这个方法私有。对其他 Execute/Esegui 方法执行相同操作。 getRichiesteForDGV() 以及与 DB 对话的其他方法也应该是由 db 变量表示的类型的(公共)成员。通过这种方式,您可以很好地分离数据访问和用户界面之间的关注点。如果不使用该类型的公共成员,您的应用程序就无法访问数据库。

最后,我删除了名称中的 WithParams 部分,因为我认为提供不期望它们的重载是不好的做法。参数非常重要,您希望向希望使用它们的开发人员清楚地传达信息。而且由于表名并不重要,您可以使用默认的Text CommandType 调用存储过程,方法是在它们前面加上exec,这可以完全取代旧的ExecuteQuery() 方法。


解决了所有这些问题,我们终于可以解决实际问题了。 EseguiQueryWithParams() 返回一个 DataTable,但这个返回值被忽略。它从未与在getRichiesteForDGV() 中声明和返回的dt 变量相关联。修复它,连同我建议的更改,如下所示:

public DataTable getRichiesteForDGV(int id)
{
    string richiesteVestiario = "RichiesteVestiario";
    string richiesteMateriali = "RichiesteMateriali";
    string richiesteAttrezzatura = "RichiesteAttrezzatura";

    string sql = $"SELECT DISTINCT nome as Nome, Cognome As Cognome, DataConsegna as Data, '{richiesteAttrezzatura}' [Tipo Richiesta] FROM RichiesteAttrezzatura " +
                "UNION SELECT DISTINCT nome AS Nome, Cognome as Cognome, DataConsegna as Data, '{richiesteMateriali}' [Tipo Richiesta] FROM RichiesteMateriali " +
                "UNION SELECT DISTINCT nome AS Nome, Cognome as Cognome, giorno AS Data, '{richiesteVestiario}' [Tipo Richiesta] FROM RichiesteVestiario";

    // this should be a member of the `db` class now, so "db." is implied
    return EseguiQuery(sql);
}

【讨论】:

  • 哇,我在这个问题上收到了一个很好的答案!通常人们会回答但不解释我在哪里做错了或其他事情。肯定有很多东西要学,但是这个解释很清楚。谢谢先生。
猜你喜欢
  • 1970-01-01
  • 2015-07-09
  • 1970-01-01
  • 2013-08-11
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 2013-01-24
相关资源
最近更新 更多