Создать новую запись внутри метода преобразования карты классов

#csvhelper

#csvhelper

Вопрос:

Дело в том, что я анализирую файл, который выглядит примерно так.

Имя Учетная запись
Foo клиент 123
Клиент Bar 456,789

В реальных данных я делаю еще кое-что, чтобы очистить учетную запись и т. Д., Но главное — , в столбце Account. Теперь я получаю IEnumerable с 2 записями, я бы хотел получить IEnumerable с 3 записями, разделив записи на запятую в столбце Account .

Вот так.

Имя Учетная запись
Foo клиент 123
Клиент Bar 456
Клиент Bar 789

Возможно ли это с помощью CSV Helper?

Ответ №1:

 void Main()
{
    using (var sReader = new StringReader("Name,AccountnFoo client,123nBar client,"456,789""))
    using (var csvReader = new CsvHelper.CsvReader(sReader, CultureInfo.InvariantCulture))
    {
        csvReader.Read();
        csvReader.ReadHeader();
        
        var records = new List<Foo>();
        
        while (csvReader.Read())
        {
            var name = csvReader.GetField("Name");
            var account = csvReader.GetField("Account");
            
            var splitAccounts = account.Split(",");
            
            foreach(var item in splitAccounts)
            {
                records.Add(new Foo { Name = name, Account = int.Parse(item)});
            }
            
        }
        records.Dump();
    }
}

public class Foo 
{
    public string Name { get; set; }
    public int Account { get; set; }
}
 

Обновление:
Каждая строка — это запись, поэтому вы действительно не можете создать новую запись, находясь за ClassMap пределами строки. Что вы могли бы сделать , так это обернуть свой класс в другой класс , содержащий несколько List<MyClass> записей , которые вы пытаетесь создать , а затем объединить их обратно в один List<MyClass> . Если Account можно ввести string , MyClass вы могли бы обойтись без отдельного MyClassMap и просто позволить этому AutoMap() вашему классу.

 void Main()
{
    using (var sReader = new StringReader("Name,AccountnFoo client,123nBar client,"456,789""))
    using (var csvReader = new CsvHelper.CsvReader(sReader, CultureInfo.InvariantCulture))
    {
        csvReader.Configuration.RegisterClassMap<FooMap>();
        csvReader.Configuration.RegisterClassMap<MyClassMap>();
        
        var wrappedRecords = csvReader.GetRecords<Foo>();
        
        var records = wrappedRecords.SelectMany(r => r.Clients).ToList();
        
        records.Dump();
    }
}

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Map(x => x.Clients).ConvertUsing(x =>
        {
            var records = new List<MyClass>();
            
            var record = x.GetRecord<MyClass>();
            
            var splitAccounts = x.GetField("Account").Split(",");

            foreach (var item in splitAccounts)
            {
                records.Add(new MyClass { Name = record.Name, Account = int.Parse(item) });
            }
            
            return records;
        });
    }
}

public class MyClassMap : ClassMap<MyClass>
{
    public MyClassMap()
    {
        Map(x => x.Name);
    }   
}

public class Foo
{
    public List<MyClass> Clients { get; set; }
}

public class MyClass
{
    public string Name { get; set; }
    public int Account { get; set; }
}
 

Комментарии:

1. Это сработало бы, но я не упомянул, что я хотел бы выполнить преобразование на этапе преобразования столбца Account в карте классов, которую я использую.

2. Посмотрите, приблизит ли мое обновление вас к тому, чего вы пытаетесь достичь.

3. Спасибо за усилия, Дэвид. На самом деле я закончил тем, что позволил CSV Helper делать это, то есть просто разбирать строки, и после этого добавил еще один шаг очистки, чтобы обработать его с помощью нескольких строк Linq.