Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate c# model class from csv file structure

Tags:

c#

csv

The goal here is that after inputing csv file, a magic tool would output c# class with the fields from csv. Let's look at example.

Input myFile.csv:

Year,Make,Model
1997,Ford,E350
2000,Mercury,Cougar

Output myFile.cs

public class myFile
{
   public string Year;
   public string Make;
   public string Model;
}

So, the only thing I would need to fix is the types of properties. After that I would use this class with FileHelpers to read csv file. Later it would be mapped to EntityFramework class (using AutoMapper) and saved to database.

Actually, https://csv2entity.codeplex.com/ looks like is doing what I need, but it just doesn't work - I installed it and nothing changed in my Visual studio, no new template appeared. The project is totally dead. Opened source code and ... decided maybe I'll just ask this question in stackoverflow :)

FileHelpers has only a simple wizard, which allows you to manually add fields. But I have 50 fields and this is not the last time I will need to do it, so automated solution is preferred here.

I believe this problem is solved many times before, any help?

like image 382
Povilas Panavas Avatar asked Sep 19 '14 12:09

Povilas Panavas


People also ask

What is C Code generation?

Code generation from the Wolfram Language involves converting programs written in the Wolfram Language into other languages and then supporting them so that they can be executed. The Wolfram System compiler provides a system for code generation into the C language.

Can MATLAB generate C Code?

MATLAB Coder generates readable and portable C code from your MATLAB algorithms. This automated approach speeds up your design workflow and eliminates coding errors introduced by a manual translation process.

Is MATLAB Coder free?

Use any C/C++ compiler to compile and run your generated code on any hardware, from desktop systems to mobile devices to embedded hardware. The generated code is royalty-free—deploy it in commercial applications to your customers at no charge.

What is coder ceval?

coder. ceval( cfun_name ) executes the external C/C++ function specified by cfun_name . Define cfun_name in an external C/C++ source file or library. Provide the external source, library, and header files to the code generator. example.


3 Answers

Thank you Bedford, I took your code and added three things:

  • It removes symbols invalid for property names. For example "Order No." will become "OrderNo" property.
  • Ability to add property and class attributes. In my case I need [DelimitedRecord(",")] and [FieldOptional()], because I'm using FileHelpers.
  • Some columns don't have names, so it generates names itself. Naming convention is Column10, Column11 and so on.

Final code:

public class CsvToClass
{
    public static string CSharpClassCodeFromCsvFile(string filePath, string delimiter = ",", 
        string classAttribute = "", string propertyAttribute = "")
    {
        if (string.IsNullOrWhiteSpace(propertyAttribute) == false)
            propertyAttribute += "\n\t";
        if (string.IsNullOrWhiteSpace(propertyAttribute) == false)
            classAttribute += "\n";

        string[] lines = File.ReadAllLines(filePath);
        string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray();
        string[] data = lines.Skip(1).ToArray();

        string className = Path.GetFileNameWithoutExtension(filePath);
        // use StringBuilder for better performance
        string code = String.Format("{0}public class {1} {{ \n", classAttribute, className);

        for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++)
        {
            var columnName = Regex.Replace(columnNames[columnIndex], @"[\s\.]", string.Empty, RegexOptions.IgnoreCase);
            if (string.IsNullOrEmpty(columnName))
                columnName = "Column" + (columnIndex + 1);
            code += "\t" + GetVariableDeclaration(data, columnIndex, columnName, propertyAttribute) + "\n\n";
        }

        code += "}\n";
        return code;
    }

    public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName, string attribute = null)
    {
        string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray();
        string typeAsString;

        if (AllDateTimeValues(columnValues))
        {
            typeAsString = "DateTime";
        }
        else if (AllIntValues(columnValues))
        {
            typeAsString = "int";
        }
        else if (AllDoubleValues(columnValues))
        {
            typeAsString = "double";
        }
        else
        {
            typeAsString = "string";
        }

        string declaration = String.Format("{0}public {1} {2} {{ get; set; }}", attribute, typeAsString, columnName);
        return declaration;
    }

    public static bool AllDoubleValues(string[] values)
    {
        double d;
        return values.All(val => double.TryParse(val, out d));
    }

    public static bool AllIntValues(string[] values)
    {
        int d;
        return values.All(val => int.TryParse(val, out d));
    }

    public static bool AllDateTimeValues(string[] values)
    {
        DateTime d;
        return values.All(val => DateTime.TryParse(val, out d));
    }

    // add other types if you need...
}

Usage example:

class Program
{
    static void Main(string[] args)
    {
        var cSharpClass = CsvToClass.CSharpClassCodeFromCsvFile(@"YourFilePath.csv", ",", "[DelimitedRecord(\",\")]", "[FieldOptional()]");
        File.WriteAllText(@"OutPutPath.cs", cSharpClass);
    }
}

There is a link to full code and working example https://github.com/povilaspanavas/CsvToCSharpClass

like image 66
Povilas Panavas Avatar answered Oct 18 '22 05:10

Povilas Panavas


You can generate the class code with a little C# app which checks all the values for each column. You can determine which is the narrowest type each one fits:

public static string CSharpClassCodeFromCsvFile(string filePath)
{
    string[] lines = File.ReadAllLines(filePath);
    string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray();
    string[] data = lines.Skip(1).ToArray();

    string className = Path.GetFileNameWithoutExtension(filePath);
    // use StringBuilder for better performance
    string code = String.Format("public class {0} {{ \n", className);

    for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++)
    {
        code += "\t" + GetVariableDeclaration(data, columnIndex, columnNames[columnIndex]) + "\n";
    }

    code += "}\n";
    return code;
}

public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName)
{
    string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray();
    string typeAsString;

    if (AllDateTimeValues(columnValues))
    {
        typeAsString = "DateTime";
    }
    else if (AllIntValues(columnValues))
    {
        typeAsString = "int";
    }
    else if (AllDoubleValues(columnValues))
    {
        typeAsString = "double";
    } 
    else
    {
        typeAsString = "string";
    }

    string declaration = String.Format("public {0} {1} {{ get; set; }}", typeAsString, columnName);
    return declaration;
}

public static bool AllDoubleValues(string[] values)
{
    double d;
    return values.All(val => double.TryParse(val, out d));
}

public static bool AllIntValues(string[] values)
{
    int d;
    return values.All(val => int.TryParse(val, out d));
}

public static bool AllDateTimeValues(string[] values)
{
    DateTime d;
    return values.All(val => DateTime.TryParse(val, out d));
}

// add other types if you need...

You can create a command line application from this which can be used in an automated solution.

like image 21
Bedford Avatar answered Oct 18 '22 07:10

Bedford


You can create the dynamic model class from CSV using dynamic in C#. Override TryGetMember of the custom DynamicObject class and use Indexers.

A useful link: C# Linq to CSV Dynamic Object runtime column name

like image 39
Jerin Avatar answered Oct 18 '22 06:10

Jerin