【问题标题】:Insert A list of objects into SQL Server table将对象列表插入 SQL Server 表
【发布时间】:2016-01-26 03:21:43
【问题描述】:

我想在 sql server 表中插入一个对象列表。但是,目前,每次插入记录行时,我都必须打开和关闭 sql 连接。

我只是想知道是否有一种方法可以一次将所有对象插入记录列表中?这是代码sn-p。

public void InsertDataToDb()
{
    string connectionString = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
    var records = GetRecords();

    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        SqlCommand cmd =
            new SqlCommand(
                "INSERT INTO TableName (param1, param2, param3) VALUES (@param1, @param2, @param3)");
        cmd.CommandType = CommandType.Text;
        cmd.Connection = conn;
        foreach (var item in records)
        {
            cmd.Parameters.AddWithValue("@param1", item.param1);
            cmd.Parameters.AddWithValue("@param2", item.param2);
            cmd.Parameters.AddWithValue("@param3", item.param3);

            conn.Open();
            cmd.ExecuteNonQuery();
            cmd.Parameters.Clear();
            conn.Close();
        }
    }
}

【问题讨论】:

  • 您可以在一个查询中添加多行。只要确保参数是唯一的。
  • 另一种方法是使用表值参数创建存储过程
  • @JeroenvanLangen 但是如果我的列表中有 100 条记录,我怎么能一条一条地添加呢?
  • 我为你找到了一些信息:stackoverflow.com/questions/2972974/…
  • 您可能想看看这篇文章,并考虑在将来不再使用 AddWithValue。 blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…

标签: c# sql sql-server


【解决方案1】:

我正在对您的数据类型做出假设(根据实际 DbTypes 的内容,根据需要更改它们),但应该这样做:

    public void InsertDataToDb()
    {
        string connectionString = ConfigurationManager.ConnectionStrings["connection"].
            ConnectionString;
        var records = GetRecords();

        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            conn.Open();

            SqlCommand cmd =
                new SqlCommand(
                    "INSERT INTO TableName (param1, param2, param3) " +
                    " VALUES (@param1, @param2, @param3)");
            cmd.CommandType = CommandType.Text;
            cmd.Connection = conn;
            cmd.Parameters.Add("@param1", DbType.String);
            cmd.Parameters.Add("@param2", DbType.String);
            cmd.Parameters.Add("@param3", DbType.String);

            foreach (var item in records)
            {
                cmd.Parameters[0].Value = item.param1;
                cmd.Parameters[1].Value = item.param2;
                cmd.Parameters[2].Value = item.param3;

                cmd.ExecuteNonQuery();
            }

            conn.Close();
        }
    }

我还建议调用一个事务,以便所有 100 次插入都可以作为一个事务完成。

-- 编辑--

关于交易,这里是关于如何添加它:

conn.Open();   // already there -- to show you where to start the transaction

SqlTransaction trans = conn.BeginTransaction();
string sql = "INSERT INTO TableName (param1, param2, param3) " +
    "VALUES (@param1, @param2, @param3)";

SqlCommand cmd = new SqlCommand(sql, conn, trans);

然后,在您关闭连接之前(或在事务中的最后一条语句之后,其中可能包括选择、更新等):

trans.Commit();

【讨论】:

  • 感谢您的回答。他们运作良好。我想知道您推荐的事务是编写一个 T-Store 过程来一次完成所有这些工作?
  • 不,ADO.net 中的事务...我没有编译/测试这个,也不想冒险在事务片段上出错,但这很容易。我会修复它并告诉你我的意思。
  • 根据您的更新,就像旁注一样,您可以将事务包装在 using 语句中,这是一种确保事务在您离开范围而不调用 @ 时回滚的简单方法987654326@。但是,因为无论如何连接都会被关闭,所以这并不重要。
  • @Hambone 我还是觉得sql事务中的每条语句都需要,怎么一次性dump所有的数据?
  • @catlovespurple 将有 100 个请求,但所有这些请求都将在一个事务中,因此如果进程失败,它们都将被回滚,并且您不会插入一半,一半没有。 Here is a full example使用事务的代码,看到只创建了一个事务。
【解决方案2】:

你可以使用像Dapper这样的ORM

有了这个库,你可以写出这样的东西

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    conn.Execute(@"INSERT INTO TableName (param1, param2, param3) 
                   VALUES (@param1, @param2, @param3)", records);
}

【讨论】:

  • Dapper 是一个很好的库,它认为这对我的项目来说有点矫枉过正。感谢您的回答,如果我有更大/更多数据库涉及的项目,我会考虑 Dapper。
  • 这取决于你。我已经使用了数千次直接 ADO 网络方法,所以我想我理解你的立场。但在我看来,写所有这些东西是在浪费时间,特别是对于小项目
【解决方案3】:

See this answer

但如果你想更新你的,那就这样做

public void InsertDataToDb()
{
    string connectionString = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
    var records = GetRecords();

    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        StringBuilder nonQuery = new StringBuilder();
        foreach(var item in records)
        {
            nonQuery.AppendFormat("INSERT INTO TableName (param1, param2, param3) VALUES ({0}, {1}, {2});",
                item.param1,
                item.param2,
                item.param3);
        }

        SqlCommand cmd = new SqlCommand(nonQuery.ToString());

        cmd.CommandType = CommandType.Text;

        cmd.Connection = conn;

        conn.Open();

        cmd.ExecuteNonQuery();

        cmd.Parameters.Clear();

        conn.Close();
    }
}

【讨论】:

  • 使查询不参数化并不是一个好的解决方案。您正在引入安全漏洞,现在需要处理诸如正确格式化日期和在文本周围加上引号等问题。正确的方法是做同样的概念,但有参数(见Hambone's answer
  • ...怎么样?它解决了他所问的问题吗?你这么说是因为 sql 注入的安全性吗? ...而且我在写我的同时支持 Hambone 的答案。
  • 怎么样?我指出了为什么这不是一个好的解决方案的 3 个问题。
猜你喜欢
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多