【问题标题】:System.Data.SqlClient.SqlException: 'Invalid column name ' 'System.Data.SqlClient.SqlException:'无效的列名''
【发布时间】:2018-11-06 16:09:49
【问题描述】:

我正在尝试从 Visual Studio 插入数据库表,但我遇到了同样的错误,我不知道会是什么。

System.Data.SqlClient.SqlException: '无效的列名'

这是我的代码,我做了 2 个类,Gateway、Dept 和 Form1:

namespace insertar
{
    class Dept
    {   
        public string Dept_No { get; set; }
        public string DNombre { get; set; }
        public string Loc { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace insertar
{
    class Gateway
    {
        public bool Save(Dept dept)
        {
            Form1 form = new Form1();

            string connectionString = @"Data Source=DESKTOP-IE39262;Initial Catalog=Hospital;Integrated Security=True";
            SqlConnection connection = new SqlConnection(connectionString);
            //connection.Open();

            /*string query = @"INSERT INTO Dept VALUES (" + dept.Dept_No + "," + dept.DNombre +
                             "," + dept.Loc + ")";*/

            SqlCommand command = new SqlCommand("INSERT INTO Dept(Dept_No, DNombre, Loc)" + "VALUES (" + dept.Dept_No + "," + dept.DNombre +
                             "," + dept.Loc + ")", connection);
            connection.Open();
            command.ExecuteNonQuery();
            connection.Close();

            return true;
        }
    }
}

private void guardarbtn_Click(object sender, EventArgs e)
{
    Dept dept = new Dept();
    dept.Dept_No = dept_no.Text;
    dept.DNombre = dnombre.Text;
    dept.Loc = loc.Text;

    Gateway gateaway = new Gateway(); //class gateway
    gateaway.Save(dept);

    MessageBox.Show("Departamento insertado exitosamente");

    dept_no.Text = "";
    dnombre.Text = "";
    loc.Text = "";
}

【问题讨论】:

  • 你为什么不参数化你的 SQL? SQL 注入远非你的朋友。
  • 您是否真的检查过数据库以确保列存在?
  • 您的字符串不带引号传递,导致服务器将它们解释为列名。阅读如何使用SqlParameter

标签: c# sql-server visual-studio


【解决方案1】:

您的插入值导致的错误是一个字符串,因此您需要使用' 来包含您的值。

但是有一个比SQL-Injection更大的问题。

我建议你使用参数而不是连接的 SQL 语句字符串。

确保您的参数数据类型大小与您的表架构相同。

string connectionString = @"Data Source=DESKTOP-IE39262;Initial Catalog=Hospital;Integrated Security=True";
string sqlQuery = "INSERT INTO Dept (Dept_No, DNombre, Loc) VALUES (@Dept_No,@DNombre,@Loc)";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
    command.Parameters.Add("@Dept_No", SqlDbType.VarChar,100).Value = dept.Dept_No;
    command.Parameters.Add("@DNombre", SqlDbType.VarChar, 100).Value = dept.DNombre;
    command.Parameters.Add("@Loc", SqlDbType.VarChar, 100).Value = dept.Loc;
    connection.Open();
    command.ExecuteNonQuery();
}

注意

我会使用using 语句,因为Using 语句的目的是当控制到达使用结束时,它会释放该对象的using 块并释放内存。它的目的不仅仅是为了自动关闭连接,基本上它会处理连接对象,显然,连接也因此而关闭。

根据MSDN

通常,当您使用 IDisposable 对象时,您应该在 using 语句中声明和实例化它。 using 语句以正确的方式调用对象的 Dispose 方法,并且(当您如前所示使用它时)它还会导致对象本身在调用 Dispose 时立即超出范围。在 using 块中,对象是只读的,不能修改或重新分配。

using 语句可确保调用 Dispose,即使在您调用对象上的方法时发生异常也是如此。您可以通过将对象放在 try 块中,然后在 finally 块中调用 Dispose 来获得相同的结果;事实上,这就是编译器翻译 using 语句的方式。前面的代码示例在编译时扩展为以下代码(注意额外的花括号以创建对象的有限范围):

因此您可以减少代码connection.Close();,因为using 将帮助您做到这一点。

【讨论】:

  • 添加没有类型和大小的参数是个坏主意,因为它可能导致错误的类型或截断。这就是 AddWithValues 被弃用的原因
  • 感谢您的提醒,我将答案编辑为Add 和大小。
  • 您可以使用语句“堆叠”,从而减少缩进,使代码更易于阅读 (IMO)。如果您不同意,请随意更改(回滚编辑)。我也喜欢尽可能晚地打开连接(在执行之前)。在这种情况下,它应该产生 0 差异,但如果计算参数并且该计算是 CPU 密集型或“较慢”,无论出于何种原因,它都会导致数据库连接打开的时间略短。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-14
  • 2019-11-02
  • 2016-04-22
  • 2019-02-13
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
相关资源
最近更新 更多