SqlBulkCopy не работает

У меня есть DataSet, заполненный из таблицы Excel. Я хотел использовать SQLBulk Copy для вставки записей в Lead_Hdr таблицу, где LeadId - PK.

При выполнении приведенного ниже кода возникает следующая ошибка:

Данный ColumnMapping не соответствует ни одному столбцу в источнике или месте назначения

string ConStr=ConfigurationManager.ConnectionStrings["ConStr"].ToString();

using (SqlBulkCopy s = new SqlBulkCopy(ConStr,SqlBulkCopyOptions.KeepIdentity))
{
    if (MySql.State==ConnectionState.Closed)
    {
        MySql.Open();
    }

    s.DestinationTableName = "PCRM_Lead_Hdr";
    s.NotifyAfter = 10000;

    #region Comment
    s.ColumnMappings.Clear();

    #region ColumnMapping
    s.ColumnMappings.Add("ClientID", "ClientID");
    s.ColumnMappings.Add("LeadID", "LeadID");
    s.ColumnMappings.Add("Company_Name", "Company_Name");
    s.ColumnMappings.Add("Website", "Website");
    s.ColumnMappings.Add("EmployeeCount", "EmployeeCount");
    s.ColumnMappings.Add("Revenue", "Revenue");
    s.ColumnMappings.Add("Address", "Address");
    s.ColumnMappings.Add("City", "City");

    s.ColumnMappings.Add("State", "State");
    s.ColumnMappings.Add("ZipCode", "ZipCode");
    s.ColumnMappings.Add("CountryId", "CountryId");

    s.ColumnMappings.Add("Phone", "Phone");
    s.ColumnMappings.Add("Fax", "Fax");
    s.ColumnMappings.Add("TimeZone", "TimeZone");
    s.ColumnMappings.Add("SicNo", "SicNo");
    s.ColumnMappings.Add("SicDesc", "SicDesc");

    s.ColumnMappings.Add("SourceID", "SourceID");
    s.ColumnMappings.Add("ResearchAnalysis", "ResearchAnalysis");
    s.ColumnMappings.Add("BasketID", "BasketID");
    s.ColumnMappings.Add("PipeLineStatusId", "PipeLineStatusId");

    s.ColumnMappings.Add("SurveyId", "SurveyId");
    s.ColumnMappings.Add("NextCallDate", "NextCallDate");
    s.ColumnMappings.Add("CurrentRecStatus", "CurrentRecStatus");
    s.ColumnMappings.Add("AssignedUserId", "AssignedUserId");
    s.ColumnMappings.Add("AssignedDate", "AssignedDate");
    s.ColumnMappings.Add("ToValueAmt", "ToValueAmt");
    s.ColumnMappings.Add("Remove", "Remove");
    s.ColumnMappings.Add("Release", "Release");

    s.ColumnMappings.Add("Insert_Date", "Insert_Date");
    s.ColumnMappings.Add("Insert_By", "Insert_By");
    s.ColumnMappings.Add("Updated_Date", "Updated_Date");
    s.ColumnMappings.Add("Updated_By", "Updated_By");

    #endregion
    #endregion

    s.WriteToServer(sourceTable);

    s.Close();

    MySql.Close();
}

person Community    schedule 13.01.2009    source источник


Ответы (7)


Ну это правда? Существуют ли имена столбцов с обеих сторон?

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

  • нет проблем с повреждением данных в реальном времени, если импорт не удался в любой момент
  • Я могу разместить транзакцию прямо вокруг SPROC
  • Я могу заставить bcp работать без регистрации, зная, что SPROC будет зарегистрирован
  • это просто ;-p (не возиться с сопоставлениями)

И напоследок: если вы имеете дело с большими объемами данных, вы можете повысить пропускную способность, используя IDataReader (поскольку это API потоковой передачи, а DataTable - это API с буферизацией). Например, я обычно подключаю импорт CSV, используя CsvReader в качестве источника для SqlBulkCopy. В качестве альтернативы я написал прокладки вокруг XmlReader, чтобы представить каждый элемент первого уровня в виде строки в IDataReader - очень быстро.

person Marc Gravell    schedule 13.01.2009
comment
Что ж, я новичок в этом промежуточном термине, не могли бы вы немного его объяснить? - person ; 13.01.2009
comment
Промежуточная таблица - это таблица, в которую вы выгружаете свои данные. Часто у него нет индекса, поэтому запись идет быстрее. Выполняйте дамп в промежуточную таблицу, управляйте данными и записывайте из промежуточной таблицы в рабочие таблицы с помощью хранимой процедуры (оберните ее в транзакцию для защиты от повреждения). - person Michael Meadows; 13.01.2009
comment
Помните, что данные промежуточной таблицы являются временными, поэтому очистите их, прежде чем вставлять данные, и не используйте их для извлечения данных, кроме как для преобразования их для вывода в другой набор таблиц. Также помните, что поэтапные данные имеют тенденцию быть менее нормальными, чем ваши реальные данные. - person Michael Meadows; 13.01.2009

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

person Tareq    schedule 09.04.2010
comment
У меня была такая же проблема, есть активная ошибка: connect.microsoft.com/VisualStudio/feedback/details/94135/ - person marcob; 12.10.2011
comment
Я использую SQL SERVER 2008 R2. И это тоже проблема. Итак, осторожно, ppl, столбец по-прежнему чувствителен к регистру в Sql 2008, по-видимому (в 2013 году). Я также обновил свой sql server 2008 R2 до последнего пакета обновлений и т. Д. - person Harvey Darvey; 18.07.2013
comment
Каким бы замечательным ни был отзыв Марка, это должен быть принятый ответ, потому что чувствительность к регистру, вероятно, является наиболее частой причиной этой ошибки (см. Все вопросы о stackoverflow, связанные с классом SqlBulkCopy). Проблема НЕ связана с какой-либо версией SQL Server, потому что SQL Server не заботится о регистре столбцов, это класс SqlBulkCopy .NET, который обеспечивает чувствительность к регистру, и этот класс должен иметь свойство для отключения чувствительности к регистру. - person Chris Smith; 30.07.2015

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

Однако, по моему опыту, вы можете проверить следующие проблемы:

Имена столбцов совпадают в источнике и таблице Соответствие типов столбцов

Если вы думаете, что сделали это, но безуспешно. Вы можете попробовать следующее.

1 - Разрешить нули во всех столбцах таблицы 2 - закомментировать все сопоставления столбцов 3 - повторно запускать добавление одного столбца за раз, пока не обнаружишь, в чем заключается проблема

Это должно выявить ошибку

person Tony Basallo    schedule 14.01.2009

Одна из причин заключается в том, что: SqlBukCOpy чувствителен к регистру. Следуйте инструкциям:

  1. В этом случае сначала вам нужно найти свой столбец в исходной таблице с помощью метода «Содержать» в C #.
  2. Как только ваш целевой столбец сопоставлен с исходным столбцом, получите индекс этого столбца и укажите его имя в SqlBukCOpy.

Например: `

//Get Column from Source table 
  string sourceTableQuery = "Select top 1 * from sourceTable";
   DataTable dtSource=SQLHelper.SqlHelper.ExecuteDataset(transaction, CommandType.Text, sourceTableQuery).Tables[0];// i use sql helper for executing query you can use corde sw

 for (int i = 0; i < destinationTable.Columns.Count; i++)
                        {    //check if destination Column Exists in Source table
                            if (dtSource.Columns.Contains(destinationTable.Columns[i].ToString()))//contain method is not case sensitive
                            {
                                int sourceColumnIndex = dtSource.Columns.IndexOf(destinationTable.Columns[i].ToString());//Once column matched get its index
                                bulkCopy.ColumnMappings.Add(dtSource.Columns[sourceColumnIndex].ToString(), dtSource.Columns[sourceColumnIndex].ToString());//give coluns name of source table rather then destination table so that it would avoid case sensitivity
                            }

                        }
                        bulkCopy.WriteToServer(destinationTable);
                        bulkCopy.Close();
person Asad    schedule 19.08.2016

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

person Community    schedule 26.10.2009

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

P.S .: промежуточные таблицы - это окончательный способ импорта.

person jocheng    schedule 25.08.2015

Я бы согласился с идеей постановки, но вот мой подход к учету регистра. Рад, что меня критикуют на моем linq

using (SqlConnection connection = new SqlConnection(conn_str))
{
        connection.Open();
        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
        {
            bulkCopy.DestinationTableName = string.Format("[{0}].[{1}].[{2}]", targetDatabase, targetSchema, targetTable);
            var targetColumsAvailable = GetSchema(conn_str, targetTable).ToArray();
            foreach (var column in dt.Columns)
            {
                if (targetColumsAvailable.Select(x => x.ToUpper()).Contains(column.ToString().ToUpper()))
                {
                    var tc = targetColumsAvailable.Single(x => String.Equals(x, column.ToString(), StringComparison.CurrentCultureIgnoreCase));
                    bulkCopy.ColumnMappings.Add(column.ToString(), tc);
                }
            }

            // Write from the source to the destination.
            bulkCopy.WriteToServer(dt);
            bulkCopy.Close();
        }
}

и вспомогательный метод

private static IEnumerable<string> GetSchema(string connectionString, string tableName)
        {



   using (SqlConnection connection = new SqlConnection(connectionString))
        using (SqlCommand command = connection.CreateCommand())
        {
            command.CommandText = "sp_Columns";
            command.CommandType = CommandType.StoredProcedure;

            command.Parameters.Add("@table_name", SqlDbType.NVarChar, 384).Value = tableName;

            connection.Open();
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return (string)reader["column_name"];
                }
            }
        }
    }
person Dickster    schedule 09.10.2017