Member 12885549 Ответов: 1

Пустые значения записываются в базу данных в виде пустой строки вместо NULL


Я генерирую строки строк для вставки:

private StringReader MapWithHeaders(StreamReader reader, int clientId, HeadersMap dataHeadersMap, string delimiter, int uploadDataId, string dateFormat)
        {
            var lines = new HashSet<string?>();
            var headers = new List<string>();
            var i = 0;
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                var csvLineInOrder = "";
                var values = line.Split(delimiter).Select(x => x.Trim(new[] { '/', '"' })).ToList();

                if (i == 0)
                {
                    headers = values.Select(x => x.Trim(new[] { '/', '"' })).ToList();
                    csvLineInOrder = String.Join(delimiter, DataHeaders);
                    i++;
                }
                else
                {
                    var campaignColumnNameId = headers.FindIndex(x => x.Equals(dataHeadersMap.CampaignColumnName));
                    var clusterColumnNameId = headers.FindIndex(x => x.Equals(dataHeadersMap.ClusterColumnName));
                    var userIdColumnNameId = headers.FindIndex(x => x.Equals(dataHeadersMap.UserIdColumnName));
                    var channelColumnNameId = headers.FindIndex(x => x.Equals(dataHeadersMap.ChannelColumnName));

                    csvLineInOrder = values[campaignColumnNameId] + delimiter + values[clusterColumnNameId] + delimiter +
                                     values[userIdColumnNameId] + delimiter + values[channelColumnNameId];

/* e.g.: ,,11111,,7,,674 */

                }
                lines.Add(csvLineInOrder);
            }

            var stringCsv = string.Join("\n", lines);
            return new StringReader(stringCsv);
        }


затем я генерирую csvDataReader:

private async Task BulkImportCsvExtra(Stream file, int clientId, HeadersMap dataExtraHeadersMap, string delimiter, int uploadDataId, string dateFormat)
        {
            using (var reader = new StreamReader(file))
            {
                var config = new CsvConfiguration(CultureInfo.InvariantCulture);
                config.BadDataFound = null;
                config.Delimiter = delimiter;

// doesn't get triggered?
                config.TypeConverterCache.AddConverter<string>(new EmptyAsNullConverter());

                var csvStreamReader = MapWithHeaders(reader, clientId, dataExtraHeadersMap, delimiter, uploadDataId, dateFormat);
                using (var csv = new CsvReader(csvStreamReader, config))
                {
                    var dataReader = new CsvDataReader(csv);
                    
                    // Need for header parsing
                    csv.ReadHeader();
                    if (!HeadersValid(csv.Context.HeaderRecord, DataHeadersExtra))
                        throw new Exception(ExceptionCode.Import.InvalidHeaders);
                    
                    await _repository.BulkAdd(dataReader);
                }
            }
        }


и, наконец, использовать массовое копирование для добавления данных:
public async Task BulkAdd(IDataReader data)
        {
            if (Connection.State == ConnectionState.Broken || Connection.State == ConnectionState.Closed)
            {
                await Connection.OpenAsync();
            }
            using (SqlBulkCopy bulk = new SqlBulkCopy(Connection))
            {
                bulk.DestinationTableName = GetTableName();
                bulk.BatchSize = BATCH_SIZE;
                bulk.BulkCopyTimeout = 0; // for infinity write 0
                bulk.EnableStreaming = true;
                await bulk.WriteToServerAsync(data);
            }
        }


Что я уже пробовал:

однако пустые значения записываются как пустые строки, а не NULL, хотя у меня есть ограничения null по умолчанию на стороне базы данных. Я застрял здесь на целую вечность. есть идеи, как это исправить?

Я попробовал добавить нулевой конвертер:
public class EmptyAsNullConverter : CsvHelper.TypeConversion.StringConverter
   {
       public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
       {
           if (string.IsNullOrWhiteSpace(text))
               return null;
           return text;
       }
   }


но он не используется даже тогда, когда я добавляю его в качестве конвертера типов, и я не знаю, как вызвать его/решить эту проблему

1 Ответов

Рейтинг:
1

Sandeep Mewara

Вам нужно установить значение как DBNull.

Цитата:
Если в поле базы данных отсутствуют данные, можно использовать значение DBNull.Свойство value, чтобы явно присвоить объекту значение dbnull значение в поле.

Ссылаться:
Значение dbnull.Поле Значения (Система) | Microsoft Docs[^]

Пример:
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
   if (string.IsNullOrWhiteSpace(text))
       return DBNull.Value;
   return text;
}

Цитата:
В объектно-ориентированном языке программирования null означает отсутствие ссылки на объект. DBNull представляет собой неинициализированный вариант или несуществующий столбец базы данных.