Использование CSVWriter для принудительного применения длины строки - PullRequest
1 голос
/ 05 января 2020

В настоящее время я работаю над проектом по извлечению данных JSON из инструмента SaaS (через API) в базу данных SQL. В конце концов, эти данные будут использоваться для целей отчетности (в качестве источника данных в Таблице).

Вот общий процесс:

  1. Извлечение необработанных данных JSON (с использованием RestSharp).
  2. Преобразование каждой записи в POCO (с использованием * 1009) * + json2csharp для генерации классов POCO).
  3. Добавьте каждую запись с шага 2 в List<MyClassExample>.
  4. Записать все записи в файл CSV (используя CSVHelper).
  5. Импорт файла CSV в базу данных SQL.

Примечание: Эти шаги повторяются для каждого объекта . Есть около 10 объектов, каждый из которых имеет от 10 до 150 полей (столбцов). Все атрибуты POCO являются строками ( это плохо? )

Проблема : я получаю ошибки усечения, потому что я не уверен, что лучший способ определить / применить ограничение размера на каждый столбец. Некоторые из столбцов являются полями абзаца в произвольном тексте, поэтому «максимальный размер» каждого столбца может измениться , что приведет к ошибкам усечения. На стороне веб-API нет документации, которая бы гарантировала / определила конкретную c схему для данных.

Как определить схему / максимальную длину для каждого столбца ДО шага 5, чтобы я не t обрезаются ошибки усечения?

Я знаю, что могу определить максимальные длины для каждого поля в определении POCO: но у меня ~ 10 POCO с сотнями полей. Каков наилучший способ сделать это?

1 Ответ

0 голосов
/ 07 января 2020

Один из способов сделать это - запросить базу данных, чтобы определить максимальную длину текстовых столбцов. Следующее использует Dapper для запроса к базе данных SQL Server, но вы сможете изменить пример для работы с другими ORM или поставщиками базы данных. В этом примере выдается исключение, если текст длиннее максимальной длины свойства, но вы можете изменить его, чтобы вместо этого усечь строку.

public class Program
{
    public static void Main(string[] args)
    {
        var connection = "Data Source=ServerName;Initial Catalog=MyDatabase;Integrated Security=true";
        var sql = @"
SELECT 
  COLUMN_NAME as ColumnName, 
  CHARACTER_MAXIMUM_LENGTH as CharacterMaximumLength 
FROM 
  INFORMATION_SCHEMA.COLUMNS 
WHERE 
  TABLE_NAME = @TableName AND CHARACTER_MAXIMUM_LENGTH IS NOT NULL";

        List<MaxLength> maxLengths;

        using (var db = new SqlConnection(connection))
        {
            maxLengths = db.Query<MaxLength>(sql, new { TableName = "MyClassExample" }).AsList();
        }

        var records = new List<MyClassExample>
        {
            new MyClassExample {Id = 1, PropertyName = "First"},
            new MyClassExample {Id = 2, PropertyName = "Second is certainly longer than the 50 characters maximum length."}
        };

        using (var csv = new CsvWriter(Console.Out))
        {
            var classMap = new DefaultClassMap<MyClassExample>();
            classMap.AutoMap(); 
            classMap.RegisterMaxLengths(maxLengths);
            csv.Configuration.RegisterClassMap(classMap);

            csv.WriteRecords(records);
        }

        Console.ReadLine();
    }
}

public class MyClassExample
{
    public int Id { get; set; }
    public string PropertyName { get; set; }
}

public class MaxLengthConverter : StringConverter
{
    private readonly int _maxLength = 0;
    public MaxLengthConverter(int maxLength)
    {
        _maxLength = maxLength;
    }

    public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
    {
        if (value is string text)
            if (text.Length > _maxLength)
            {
                var message =   $"The text with length {text.Length} exceeds the maximum allowed length of {_maxLength}.\r\n" +
                                $"    Text: '{text}'\r\n" +
                                $"    Property: {memberMapData.Member?.Name}\r\n" +
                                $"    TypeConverter: '{memberMapData.TypeConverter?.GetType().FullName}'";
                throw new TypeConverterException(this, memberMapData, value, row.Context, message);
            }

        return base.ConvertToString(value, row, memberMapData);
    }
}

public class MaxLength
{
    public string ColumnName { get; set; }
    public int CharacterMaximumLength { get; set; }
}

public static class CsvHelpExtensions
{
    public static void RegisterMaxLengths<T>(this ClassMap<T> map, IEnumerable<MaxLength> maxLengths)
    {
        foreach (var property in typeof(T).GetProperties())
        {
            var maxLength = maxLengths.Where(m => m.ColumnName.ToLower() == property.Name.ToLower()).FirstOrDefault();
            if (maxLength != null)
                map.Map(typeof(T), property, true).TypeConverter(new MaxLengthConverter(maxLength.CharacterMaximumLength));
        }
    }
}
...