Sora Teichman
Sora Teichman

Reputation: 184

How do I map from a string to a custom type when importing a csv using ChoETL?

I'm importing a csv of sales orders into CsvSalesOrder objects. The CsvSalesOrder has an Address property, and its properties are of a custom type called CustomString. How can I convert the strings into the CustomString types when importing them? My CustomString class:

public struct CustomString
{
    public string Value { get; }

    public CustomString(string val)
    {
        if (string.IsNullOrWhiteSpace(val))
        {
            Value = null;
        }
        else
        {
            Value = val.ToUpper();
        }
    }

    public static implicit operator string(CustomString s) => s.Value;
    public static explicit operator CustomString(string s) => new CustomString(s);
    public override string ToString() => Value;
}

My mapping setup:

var config = new ChoCSVRecordConfiguration<T>()
        .WithFirstLineHeader()
        .Configure(c => c.ThrowAndStopOnMissingField = false)
        .Configure(c => c.IgnoreEmptyLine = true)
        .Configure(c => c.FileHeaderConfiguration.IgnoreColumnsWithEmptyHeader = true);

foreach (var header in headers)
{
    if (mapping.TryGetValue(header, out var propName))
        config.Map(propName, header);
}

My import code:

using var reader = new ChoCSVReader<T>(stream, config)
        .WithMaxScanRows(2)
        .QuoteAllFields()
        .IgnoreFieldValueMode(ChoIgnoreFieldValueMode.Any);
return reader.AsTypedEnumerable<T>();

The Address fields are all null when I try to import. I tried adding a type converter as documented here, but it did not work.

ChoCSVRecordFieldConfiguration customStringConfig = new ChoCSVRecordFieldConfiguration("Address1");
customStringConfig.AddConverter(TypeDescriptor.GetConverter(typeof(CustomString)));
config.CSVRecordFieldConfigurations.Add(customStringConfig);

Upvotes: 0

Views: 134

Answers (3)

Sora Teichman
Sora Teichman

Reputation: 184

I updated my code thanks to @Cinchoo's input.Here's the updated part:

using (var reader = new ChoCSVReader<T>(stream, config)
            .WithMaxScanRows(2)
            .QuoteAllFields()
            .IgnoreFieldValueMode(ChoIgnoreFieldValueMode.Any)
            )
        {
            return reader.AsTypedEnumerable<T>().ToList();
        }

I had to add .ToList() to get the list before the reader was disposed of. I also updated the using syntax and the version of the ChoETL package.

Upvotes: 0

Cinchoo
Cinchoo

Reputation: 6332

You do not need custom value converters, as CustomString already implemented implicit type conversion operators.

Here is the sample, on how do without converters

https://dotnetfiddle.net/uFrlCg

Here is a sample using converters

https://dotnetfiddle.net/ia5e50

Upvotes: 0

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112712

Add your own TypeConverter:

public class CustomStringTypeConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string s) {
            return new CustomString(s);
        } else {
            return base.ConvertFrom(context, culture, value);
        }
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is CustomString customString) {
            return customString.Value;
        } else {
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

I don't know ChoETL , therefore I am not sure if this fixes the problem or if there are other configuration problems.

Upvotes: 0

Related Questions