Итак, у меня есть база данных с информацией о местоположении сайта, которая содержит 27 столбцов. Я написал функцию массового импорта, которая использует файл CSV и позволяет изменять информацию. Все работает хорошо, когда CSV-файл содержит информацию в каждом столбце, но когда есть пустая строка / ноль, он отправляет пустую строку в базу данных и стирает то, что было раньше.

Для того, чтобы иметь возможность быстро обновлять определенные атрибуты в базе данных, моему клиенту нужно только ввести первичный ключ сайта (который я закодировал для импорта, чтобы сделать обновляемым) и заполнить любой другой атрибут без необходимости заполнять остальные. Так, например, CSV-файл для местоположения может выглядеть примерно так:

SITE32,,,,BS,11111,,43607,123566789,123456789,2.2.2.2,1.1.1.1.1,1.1.1.1,0,Test,Test,Testing,2,12123,5002,N/A,4,00201,3,000,3703,5

Скажем, этот сайт уже существует в базе данных, я просто хочу обновить заполненные поля. Те, которые оставлены пустыми, должны оставаться такими же.

Это код, который у меня есть

       protected void btnBulkSite_click(object sender, EventArgs e)
            {

                if (FileUpLoad1.HasFile)
                {
                    FileUpLoad1.SaveAs(@"C:\temp\" + FileUpLoad1.FileName);
                    btnBulkSite.Text = "File Uploaded: " + FileUpLoad1.FileName;
                }
                else
                {
                    btnBulkSite.Text = "No File Uploaded.";
                }
                DataTable tblcsv = new DataTable();

                tblcsv.Columns.Add("SERVER_ID", typeof(string));
                tblcsv.Columns.Add("SITE_NAME", typeof(string));
                tblcsv.Columns.Add("SITE_ADDRESS", typeof(string));
                tblcsv.Columns.Add("SITE_CITY", typeof(string));
                tblcsv.Columns.Add("SITE_STATE", typeof(string));
                tblcsv.Columns.Add("SITE_ZIPCODE", typeof(string));
                tblcsv.Columns.Add("SITE_COUNTY", typeof(string));
                tblcsv.Columns.Add("SITE_INTERNALZIP", typeof(string));
                tblcsv.Columns.Add("SITE_PHONE_NUM", typeof(string));
                tblcsv.Columns.Add("SITE_FAX_NUM", typeof(string));
                tblcsv.Columns.Add("SERVER_SUBNET_ADDR", typeof(string));
                tblcsv.Columns.Add("SERVER_IP_ADDR", typeof(string));
                tblcsv.Columns.Add("SERVER_GATEWAY_ADDR", typeof(string));
                tblcsv.Columns.Add("COSTCENTER_NUM");
                tblcsv.Columns.Add("DCMF_NAME", typeof(string));
                tblcsv.Columns.Add("LU_ID", typeof(string));
                tblcsv.Columns.Add("XIDPU_ID", typeof(string));
                tblcsv.Columns.Add("TRAININGSITE_IND");
                tblcsv.Columns.Add("PBA_FICS_NUM");
                tblcsv.Columns.Add("PBA_CITY_ID", typeof(string));
                tblcsv.Columns.Add("REGION_NAME", typeof(string));
                tblcsv.Columns.Add("SITETYPE_ID");
                tblcsv.Columns.Add("PBA_OFFICE_ID", typeof(string));
                tblcsv.Columns.Add("SITEORIGIN_ID");
                tblcsv.Columns.Add("REGION_ID", typeof(string));
                tblcsv.Columns.Add("PBA_BANK_ID", typeof(string));
                tblcsv.Columns.Add("SITE_REGION_ID");



                System.IO.StreamReader stream = new System.IO.StreamReader(FileUpLoad1.PostedFile.InputStream);

                string ReadCSV = stream.ReadToEnd();
                foreach (string csvRow in ReadCSV.Split('\n'))
                    {

                        if (!string.IsNullOrEmpty(csvRow))
                        {
                        tblcsv.Rows.Add();
                        int count = 0;

                        foreach (string FileRec in csvRow.Split(','))
                        {
                            tblcsv.Rows[tblcsv.Rows.Count - 1][count] = FileRec;

                            count++;
                        }
                    }
                }

                RemoveAllNullColumnsFromDataTable(tblcsv);

            }

  public void RemoveAllNullColumnsFromDataTable(DataTable tblcsv)
        {
            for (int h = 0; h < tblcsv.Rows.Count; h++)
            {
                if (tblcsv.Rows[h].IsNull(0) == true)
                {
                    tblcsv.Rows[h].Delete();
                }

            }
            tblcsv.AcceptChanges();
            foreach (var column in tblcsv.Columns.Cast<DataColumn>().ToArray())
            {
                if (tblcsv.AsEnumerable().All(dr => dr.IsNull(column)))
                    tblcsv.Columns.Remove(column);
            }
            tblcsv.AcceptChanges();
            InsertCSVRecords(tblcsv);
        }

        public void InsertCSVRecords(DataTable csvdt)
        {
            connection();

            //SqlBulkCopy objbulk = new SqlBulkCopy(con);
            var objbulk = new BulkOperation(con);
            objbulk.AllowUpdatePrimaryKeys = true;
            objbulk.DestinationTableName = "SITE_INFO";


            objbulk.ColumnMappings.Add("SERVER_ID", "SERVER_ID", true);
            objbulk.ColumnMappings.Add("SITE_NAME", "SITE_NAME");
            objbulk.ColumnMappings.Add("SITE_ADDRESS", "SITE_ADDRESS");
            objbulk.ColumnMappings.Add("SITE_CITY", "SITE_CITY");
            objbulk.ColumnMappings.Add("SITE_STATE", "SITE_STATE");
            objbulk.ColumnMappings.Add("SITE_ZIPCODE", "SITE_ZIPCODE");
            objbulk.ColumnMappings.Add("SITE_COUNTY", "SITE_COUNTY");
            objbulk.ColumnMappings.Add("SITE_INTERNALZIP", "SITE_INTERNALZIP");
            objbulk.ColumnMappings.Add("SITE_PHONE_NUM", "SITE_PHONE_NUM");
            objbulk.ColumnMappings.Add("SITE_FAX_NUM", "SITE_FAX_NUM");
            objbulk.ColumnMappings.Add("SERVER_SUBNET_ADDR", "SERVER_SUBNET_ADDR");
            objbulk.ColumnMappings.Add("SERVER_IP_ADDR", "SERVER_IP_ADDR");
            objbulk.ColumnMappings.Add("SERVER_GATEWAY_ADDR", "SERVER_GATEWAY_ADDR");
            objbulk.ColumnMappings.Add("COSTCENTER_NUM", "COSTCENTER_NUM");
            objbulk.ColumnMappings.Add("DCMF_NAME", "DCMF_NAME");
            objbulk.ColumnMappings.Add("LU_ID", "LU_ID");
            objbulk.ColumnMappings.Add("XIDPU_ID", "XIDPU_ID");
            objbulk.ColumnMappings.Add("TRAININGSITE_IND", "TRAININGSITE_IND");
            objbulk.ColumnMappings.Add("PBA_FICS_NUM", "PBA_FICS_NUM");
            objbulk.ColumnMappings.Add("PBA_CITY_ID", "PBA_CITY_ID");
            objbulk.ColumnMappings.Add("REGION_NAME", "REGION_NAME");
            objbulk.ColumnMappings.Add("SITETYPE_ID", "SITETYPE_ID");
            objbulk.ColumnMappings.Add("PBA_OFFICE_ID", "PBA_OFFICE_ID");
            objbulk.ColumnMappings.Add("SITEORIGIN_ID", "SITEORIGIN_ID");
            objbulk.ColumnMappings.Add("REGION_ID", "REGION_ID");
            objbulk.ColumnMappings.Add("PBA_BANK_ID", "PBA_BANK_ID");
            objbulk.ColumnMappings.Add("SITE_REGION_ID", "SITE_REGION_ID");



            con.Open();
            objbulk.BulkUpdate(csvdt);

            con.Close();

        }

Моя логика заключается в том, что как только информация импортируется из файла CSV, она перемещается в таблицу данных, и если она содержит нулевое значение, столбец в таблице данных удаляется. И поэтому нет ничего, что можно было бы сопоставить с сопоставлениями столбцов BulkUpdate, и, следовательно, нет данных, которые должны быть отправлены в базу данных для этого столбца.

Однако по какой-то причине это не работает, и я не знаю, почему ... есть ли способ лучше?

Любая помощь будет оценена, спасибо.

0
ouro 15 Апр 2016 в 20:19

2 ответа

Лучший ответ

Есть множество решений, чтобы добраться туда, где вам нужно.

Одна проблема, которую я вижу, заключается в том, что если человек загружает элементы с несколькими строками, и эти строки имеют разные данные (скажем, один столбец пуст в одной строке, но заполнен во второй строке), это приведет к его поломке, поскольку столбец будет иметь удалил себя.

SITE32,,1,2,,...
SITE32,1,2,,,...

В этом случае столбцы 1, 3 и 4 (здесь с нулевым основанием) будут удалены, поскольку они имеют нулевые значения, которые нарушили бы вашу намеченную цель. Ваша логика в том виде, в котором она написана, будет работать, только если каждая строка содержит данные в одних и тех же столбцах.

Я бы рекомендовал загрузить данные во временную таблицу и завершить задачу на SQL, что даст вам больше контроля над процессом загрузки данных. Если у вас есть доступ к базе данных, напишите хранимую процедуру, а затем передайте каждую строку таблицы данных в хранимую процедуру и выполните операцию обновления оттуда.

SqlCommand cmd = new SqlCommand("",conn());
cmd.CommandText = "CREATE TABLE #tmp (
[SERVER_ID] NVARCHAR(MAX),
[SITE_NAME] NVARCHAR(MAX),
[SITE_ADDRESS] NVARCHAR(MAX),
[SITE_CITY] NVARCHAR(MAX),
[SITE_STATE] NVARCHAR(MAX),
[SITE_ZIPCODE] NVARCHAR(MAX),
[SITE_COUNTY] NVARCHAR(MAX),
[SITE_INTERNALZIP] NVARCHAR(MAX),
[SITE_PHONE_NUM] NVARCHAR(MAX),
[SITE_FAX_NUM] NVARCHAR(MAX),
[SERVER_SUBNET_ADDR] NVARCHAR(MAX),
[SERVER_IP_ADDR] NVARCHAR(MAX),
[SERVER_GATEWAY_ADDR] NVARCHAR(MAX),
[COSTCENTER_NUM] NVARCHAR(MAX),
[DCMF_NAME] NVARCHAR(MAX),
[LU_ID] NVARCHAR(MAX),
[XIDPU_ID] NVARCHAR(MAX),
[TRAININGSITE_IND] NVARCHAR(MAX),
[PBA_FICS_NUM] NVARCHAR(MAX),
[PBA_CITY_ID] NVARCHAR(MAX),
[REGION_NAME] NVARCHAR(MAX),
[SITETYPE_ID] NVARCHAR(MAX),
[PBA_OFFICE_ID] NVARCHAR(MAX),
[SITEORIGIN_ID] NVARCHAR(MAX),
[REGION_ID] NVARCHAR(MAX),
[PBA_BANK_ID] NVARCHAR(MAX),
[SITE_REGION_ID] NVARCHAR(MAX)
);
conn.Open();
cmd.ExecuteNonQuery();

SqlBulkCopy bc = new SqlBulkCopy();
bc.DestinationTableName = "#tmp";
bc.BulkCopyTimeout = 600;
bc.WriteToServer(dt);
bc.Close();

cmd.CommandText = "UPDATE t SET t.SERVER_ID = CASE WHEN tmp.SERVER_ID <> '' THEN tmp.SERVER_ID ELSE t.SERVER_ID END, ..... t.SITE_REGION_ID = CASE WHEN tmp.SITE_REGION_ID <> '' THEN tmp.SERVER_ID ELSE t.SERVER_ID END FROM Table t INNER JOIN #tmp AS tmp ON t.SERVER_ID = tmp.SERVER_ID";
cmd.ExecuteNonQuery();
conn.Close();

Приведенный выше код необходимо скорректировать и отредактировать для ваших целей. Это всего лишь пример. Обратите внимание, что соединение не может быть закрыто между вашими операциями, иначе временная таблица будет удалена. Вам необходимо выполнить как вставку, так и обновление, используя одно и то же соединение.

1
Boyd P 15 Апр 2016 в 20:07

Составьте индивидуальный отчет об обновлении
Вы можете связать обновления

  update [test].[dbo].[Table_1] set value1 = 'newOne' where iden = 1;
  update [test].[dbo].[Table_1] set value1 = 'newTwo' where iden = 2;

Но это будет открыта для SQL-инъекции, поэтому вам следует использовать параметры
Я не уверен, можно ли объединить несколько обновлений на основе параметров в один
Если нет, и скорость является проблемой, я бы сделал асинхронное обновление, чтобы вы создавали следующее обновление во время выполнения текущего.

0
paparazzo 15 Апр 2016 в 17:40