【问题标题】:INSERT values from a list to database从列表中插入值到数据库
【发布时间】:2020-07-22 13:04:48
【问题描述】:

我想解析一个 CSV 文件,将其存储在一个列表中,然后将该列表中的值插入到数据库中。这是我的代码示例。 我还在学习,所以如果不清楚,我会进一步解释。但想法是逐行解析 csv 文件,然后将每一行插入我的数据库中。提前谢谢你。

public class SKU : List<string[]>
{
    public string SKU_ID { get; set; }
    public string SKU_Name { get; set; }
    public string Code { get; set; }
    public string Product_Name { get; set; }
    public string DistributionCenter_Name { get; set; }

    internal static SKU ParseRow(string row)
    {
        var columns = row.Split(';');
        return new SKU()
        {
            SKU_ID = columns[0],
            SKU_Name = columns[1],
            Code = columns[2],
            Product_Name = columns[3],
            DistributionCenter_Name = columns[4],
        };
    }
}

在脚本中,我将每一列命名为 csv 文件和我的数据库中的名称。

我的主要如下

class Programm
{
      static void Main(string[] args)
      {
          var sku_info = ProcessCSV("skutest1.csv");                
          SqlConnection conn = new SqlConnection();    
          conn.ConnectionString = @"...";
          foreach (var information in sku_info)
          {    
              using SqlConnection connection = new SqlConnection(conn.ConnectionString);

              string commandString = ("INSERT INTO SKU VALUES ('" + information.SKU_ID + " "+information.SKU_Name+" "+information.Code+" "+information.Product_Name+" "+information.DistributionCenter_Name+"')");

              conn.Open();
              SqlTransaction transaction = conn.BeginTransaction();    
              SqlCommand cmd = new SqlCommand(commandString, conn, transaction);
              cmd.ExecuteNonQuery();   
              transaction.Commit();
          }

          Console.ReadKey();
      }

      private static List<SKU> ProcessCSV(string path)
      {
          return File.ReadAllLines("C:/.../skutest1.csv").Where(row => row.Length > 0).Select(SKU.ParseRow).ToList();
      }
}

【问题讨论】:

  • 您的commandString 大楼非常危险。请阅读stackoverflow.com/questions/14376473/…
  • 那么你的问题是什么?如果我不得不猜测这是关于您从 INSERT 语句中得到的错误,因为您使用的是字符串连接(不正确),而不是参数,但我不应该猜测。
  • 始终使用参数化 sql 并避免字符串连接向 sql 语句添加值。这可以缓解 SQL 注入漏洞并确保将值正确传递给语句。请参阅 How can I add user-supplied input to an SQL statement?Exploits of a Mom
  • @ZoharPeled 感谢您的文章,这将有很大帮助!
  • @Igor 非常感谢你!我仍然缺乏语法知识和编码的好方法,您的链接将有很大帮助!

标签: c# database list csv localdb


【解决方案1】:

在服务器上加载文件的最快方法是使用BULK INSERT,例如:

BULK INSERT someTable
FROM 'pathtofile`
WITH ( FORMAT = 'CSV' )

您可以通过使用 ADO.NET 的 SqlBulkCopy 类对从客户端发送的数据执行 BULK INSERT 操作来执行类似的操作。 SqlBulkCopy 需要一个 DataTable 或 IDbDataReader 参数。您可以为此使用CsvHelper' CsvDataReader。 CsvDataReader 解析 CSV 文件并生成 SqlBulkCopy 所需的IDbDataReader 接口。

代码可以这么简单:

using var txtReader = File.OpenText(pathToCSV);

var reader = new CsvReader(txtReader,CultureInfo.InvariantCulture);
using var dbReader = new CsvDataReader(reader);

var bcp = new SqlBulkCopy(cns);
bcp.ColumnMappings.Add("sku_id","sku_id");
bcp.ColumnMappings.Add("sku_name","sku_name");
...

bcp.DestinationTableName = table;
bcp.WriteToServer(dbReader);

如果没有映射,SqlBulkCopy 将按照它们在文件中出现的顺序发送列。如果这与表格列的顺序不匹配,则会出现错误或更糟糕的情况,导致数据混淆

【讨论】:

  • 哦,我明白了,我曾经在 SQL 上遇到过 BULK COPY,但我不知道 ADO.NET 中有一个类,谢谢!我试试看
【解决方案2】:

Here's 一个关于构建参数化 commandstring 的简短教程 - 这是一种更安全的插入数据库的方法。

以下是如何参数化插入的示例:

string commandString = (@"INSERT INTO SKU VALUES (@sku_id, @sku_name, @code, @product_name, @distributioncenter_name");

conn.Open();
SqlTransaction transaction = conn.BeginTransaction();

SqlCommand cmd = new SqlCommand(commandString, conn, transaction);

cmd.Parameters.Add(new SqlParameter("@sku_id", information.SKU_ID));
cmd.Parameters.Add(new SqlParameter("@sku_name", information.SKU_Name));
cmd.Parameters.Add(new SqlParameter("@code", information.Code));
cmd.Parameters.Add(new SqlParameter("@product_name", information.Product_Name));
cmd.Parameters.Add(new SqlParameter("@distributioncenter_name", information.DistributionCenter_Name));

cmd.ExecuteNonQuery();

transaction.Commit();

【讨论】:

  • @hugo-volpi 谢谢。如果此解决方案适合您,请单击我的答案左侧的灰色复选标记。这会将答案标记为您“接受”并奖励我一些声誉。
  • 确定!我会试试的
  • @HugoVolpi - 这是参数的正确使用。我唯一建议的更改是: 1) 将实现 IDisposable 的类型包装在 using 块中(此处未显示代码中的 SqlTransaction、SqlCommand 和 SqlConnection)。请在适用的情况下为SqlParameter 构造函数提供size 参数,并根据模式中列的长度保持该常量。在 INSERT 语句中包含列名,以确保在对架构中的列重新排序时代码不会中断。
  • ^-- continued 除非您想让所有插入都失败,否则不需要事务,在这种情况下将其移至foreach 循环之外并在循环后提交完成执行。
  • @HugoVolpi 请点击imgur.com/a/SrYT2MF
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-01
  • 1970-01-01
相关资源
最近更新 更多