Search code examples
c#asp.net-corecsvhelper

CSVHelper - import convert name from CSV to object with equal name property


I'm importing a row with CSVHelper into the following class:

public class RequestMonitoring
{
    public string PNdsPn { get; set; }

    [Required]
    public virtual Stamp PUsrCrStatus { get; set; } 
    
    // many other properties
} 

with Stamp looking like this:

public class Stamp
{
    public int Weight { get; set; }

    [Required]
    public string MachineName { get; set; }  
    
    // many other properties
}

And a CSV looking like this:

$P_NDS_PN;#P_USR_CR_Staus; ...
CTD_037453;SYS complete; ...

Where "SYS complete" is the "MachineName" of the stamp.

But the typeconversion doesn't work like i expected. If i'm using a CustomTypeConverter it doesn't fire it's ConvertFromString method except i change the "PUsrCrStatus" property to type string which makes no sense in my opinion.

So i tried inline conversion with ConvertUsing like this:

classMap.Map(requestMonitoring => requestMonitoring.PUsrCrStatus)
.ConvertUsing(row = > _context.Stamps.SingleOrDefault(stamp => stamp.MachineName == row.GetField("#P_USR_CR_Status"));

But this works only if i put [Ignore] attributes on every attribute except "MachineName" in the Stamp model, which is a bad if want to import Stamps from a different CSV later on.

So i tried to define these ignores in the classmap like:

classMap.Map(requestMonitoring => requestMonitoring.PUsrCrStatus.Weight).Ignore();

and tried also:

classMap.Map(typeof(Stamp),typeof(Stamp).GetProperties().SingleOrDefault(p => p.Name == "Id") ).Ignore();

but they both didn't work, it still tells me that no column with name "Weight" is there in the CSV.

Can anyone please help me to get this working? Thanks in advance


Solution

  • I maybe understand what you are trying to do. You might want to rethink the var classMap = csv.Configuration.AutoMap<RequestMonitoring>(); you had in your other question if the only field you want to map in the Stamp class is MachineName. AutoMap is mapping all the properties of PUsrCrStatus. See if this gets you closer to what you are trying to do.

    static void Main(string[] args)
    {
        using (var stream = new MemoryStream())
        using (var writer = new StreamWriter(stream))
        using (var reader = new StreamReader(stream))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            writer.WriteLine("$P_NDS_PN,#P_USR_CR_Status");
            writer.WriteLine("test,StampName");
            writer.Flush();
            stream.Position = 0;
    
            var classMap = new DefaultClassMap<RequestMonitoring>();
    
            foreach (var property in typeof(RequestMonitoring).GetProperties())
            {
                if (property.Name == "PUsrCrStatus") { continue; }
                var columnName = property.Name switch
                {
                    "PNdsPn" => "$P_NDS_PN",
                    { } x when x.StartsWith("PUsrCr") => property.Name.Replace("PUsrCr", "#P_USR_CR_"),
                    _ => property.Name
                };
                classMap.Map(typeof(RequestMonitoring), property).Name(columnName);
            }
    
            classMap.Map(requestMonitoring => requestMonitoring.PUsrCrStatus.MachineName).Name("#P_USR_CR_Status");
    
            csv.Configuration.RegisterClassMap(classMap);
    
            var records = csv.GetRecords<RequestMonitoring>().ToList();
        }
    }
    

    Or you could use a custom TypeConverter to map PUsrCrStatus

    static void Main(string[] args)
    {
        using (var stream = new MemoryStream())
        using (var writer = new StreamWriter(stream))
        using (var reader = new StreamReader(stream))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            writer.WriteLine("$P_NDS_PN,#P_USR_CR_Status");
            writer.WriteLine("test,StampName");
            writer.Flush();
            stream.Position = 0;
    
            var classMap = new DefaultClassMap<RequestMonitoring>();
    
            foreach (var property in typeof(RequestMonitoring).GetProperties())
            {
                var columnName = property.Name switch
                {
                    "PNdsPn" => "$P_NDS_PN",
                    { } x when x.StartsWith("PUsrCr") => property.Name.Replace("PUsrCr", "#P_USR_CR_"),
                    _ => property.Name
                };
                classMap.Map(typeof(RequestMonitoring), property).Name(columnName);
            }
    
            classMap.Map(requestMonitoring => requestMonitoring.PUsrCrStatus).TypeConverter<StampTypeConverter>();
    
            csv.Configuration.RegisterClassMap(classMap);
    
            var records = csv.GetRecords<RequestMonitoring>().ToList();
        }
    }
    
    public class StampTypeConverter : DefaultTypeConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            return new Stamp { MachineName = text };
        }
    }