C #: отображение типа данных - PullRequest
0 голосов
/ 03 июня 2011

Мне нужно написать ужасный интерфейс для импорта данных в новую базу данных из сотен файлов данных из нашего старого приложения, в котором все жестко закодировано (отображаемые данные напоминают электронные таблицы Excel, и это позволяет нам экспортировать данные в Значения, разделенные запятыми).

Я могу все это прочитать, с именами заголовков.

Исходя из этого, я могу создать имя для столбца, который будет использоваться в базе данных Sql CE.

В настоящее время данные состоят из float, int, DateTime, bit, char и string.

Я придумал способ сделать это (непроверенный на всех наших данных), но любая помощь от кого-то, кто знает, как кодировать это лучше, будет очень признателен.

Код ниже не обязательно читать, если кто-то просто не понимает, о чем я спрашиваю.

public enum MyParameterType { NA, Float, Bool, Char, Date, Int, String }

class MyParameter {

public MyParameter(string name, string value) {
  if (String.IsNullOrEmpty(name) || String.IsNullOrEmpty(value)) {
    throw new NotSupportedException("NULL values are not allowed.");
  }
  Name = name.Trim();
  Value = value.Trim();
  Type = MyParameterType.NA;
  if (-1 < Value.IndexOf('.')) { // try float
    float f;
    if (float.TryParse(Value, out f)) {
      string s = f.ToString();
      if (s == Value) {
        Parameter = new SqlCeParameter(AtName, SqlDbType.Float) { Value = f };
        Type = MyParameterType.Float;
      }
    }
  }
  if (Type == MyParameterType.NA) {
    bool b;
    if (bool.TryParse(Value, out b)) {
      Parameter = new SqlCeParameter(AtName, SqlDbType.Bit) { Value = b };
      Type = MyParameterType.Bool;
    }
  }
  if (Type == MyParameterType.NA) {
    if (Value.Length == 1) {
      char c = Value[0];
      Parameter = new SqlCeParameter(AtName, SqlDbType.Char) { Value = c };
      Type = MyParameterType.Char;
    }
  }
  if (Type == MyParameterType.NA) {
    DateTime date;
    if (DateTime.TryParse(Value, out date)) {
      Parameter = new SqlCeParameter(AtName, SqlDbType.DateTime) { Value = date };
      Type = MyParameterType.Date;
    }
  }
  if (Type == MyParameterType.NA) {
    if (50 < Value.Length) {
      Value = Value.Substring(0, 49);
    }
    Parameter = new SqlCeParameter(AtName, SqlDbType.NVarChar, 50) { Value = this.Value };
    Type = MyParameterType.String;
  }
}

public string AtName { get { return "@" + Name; } }

public string Name { get; set; }

public MyParameterType Type { get; set; }

public SqlCeParameter Parameter { get; set; }

public string Value { get; set; }

}

Больше всего меня беспокоит то, что я не хочу ошибочно интерпретировать один из входных данных (например, логическое значение как символ).

Я также ищу способ сравнения новых экземпляров MyParameter (т. Е. Если он меньше одного типа, попробуйте другой тип).

Бонусные баллы за просмотр новых классных выражений, генерирующих это!

Ответы [ 3 ]

2 голосов
/ 03 июня 2011

Учитывая некоторые абстрактные CsvReader:

using (var reader = new CsvReader(file))
{
    TableGuess table = new TableGuess { Name = file };

    // given: IEnumerable<string> CsvReader.Header { get; }
    table.AddColumns(reader.Header);

    string[] parts;
    while (null != (parts = reader.ReadLine()))
    {
        table.AddRow(parts);
    }
}

Ваш ColumnGuess:

class ColumnGuess
{
    public string Name { get; set; }
    public Type Type { get; set; }
    public int Samples { get; private set; }

    public void ImproveType(string value)
    {
        if (this.Samples > 10) return;
        this.Samples++;

        float f; bool b; DateTime d; int i;
        if (Single.TryParse(value, out f))
        {
            this.Type = typeof(float);
        }
        else if (Boolean.TryParse(value, out b))
        {
            this.Type = typeof(bool);
        }
        else if (DateTime.TryParse(value, out d))
        {
            this.Type = typeof(DateTime);
        }
        else if (value.Length == 1 && this.Type == null && !Char.IsDigit(value[0]))
        {
            this.Type = typeof(char);
        }
        else if (this.Type != typeof(float) && Int32.TryParse(value, out i))
        {
            this.Type = typeof(int);
        }
    }
}

TableGuess будет содержать угаданные столбцы и строки:

class TableGuess
{
    private List<string[]> rows = new List<string[]>();
    private List<ColumnGuess> columns;

    public string Name { get; set; }

    public void AddColumns(IEnumerable<string> columns)
    {
        this.columns = columns.Select(cc => new ColumnGuess { Name = cc })
                              .ToList();
    }

    public void AddRow(string[] parts)
    {
        for (int ii = 0; ii < parts.Length; ++ii)
        {
            if (String.IsNullOrEmpty(parts[ii])) continue;
            columns[ii].ImproveType(parts[ii]);
        }

        this.rows.Add(parts);
    }
}

Вы можете добавить к TableGuess метод AsDataTable():

public DataTable AsDataTable()
{
    var dataTable = new dataTable(this.Name);
    foreach (var column in this.columns)
    {
        dataTable.Columns.Add(new DataColumn(
            column.Name,
            column.Type ?? typeof(string)));
    }

    foreach (var row in this.rows)
    {
        object[] values = new object[dataTable.Columns.Count];
        for (int cc = 0; cc < row.Length; ++cc)
        {
            values[cc] = Convert.ChangeType(row[cc],
                dataTable.Columns[cc].DataType);
        }

        dataTable.LoadRow(values, false);
    }

    return dataTable;
}

Вы можете использовать SqlCeDataAdapter для перемещения данных в DataTable (после добавления самой таблицы вбазы данных).

2 голосов
/ 03 июня 2011

Я думаю, что проблема не в этом коде, это похоже на способ узнать, потому что вы всегда получаете параметры в виде строки, я думаю, вы можете попробовать это лучше, но на этапе извлечения данных,

Может быть, со столбцами заголовков вы можете "разобрать их" по типу ..

и попробовать

Convert.ChangeType(yourValue, typeof(string, double,etc))
1 голос
/ 03 июня 2011

Как насчет этого псевдокода - я считаю, это должно быть достаточно быстро для вас. Это очень псевдо - так что "string", "char" и т. Д. Являются просто заполнителями для значения enum или чего-то еще, что вам нравится.

For first data row in data file
  For each column in row
    TypeOfCol(column) = <best first guess>
  Next
Next

For each data row in data file
  For each column in row
    If TypeOfCol(column) = "string"
      Continue For
    If TypeOfCol(column) = "char"
      If columnValue has more than one character
        TypeOfCol(column) = "string"
        Continue For
    If TypeOfCol(column) = "bit"
      If columnValue isn't 1 or 0
        TypeOfCol(column) = "int" // Might not be an int - next If will pick up on that...
    If TypeOfCol(column) = "int"
      If columnValue isn't integer
        TypeOfCol(column) = "float"
    If TypeOfCol(column) = "float"
      If columnValue isn't a float
        TypeOfCol(column) = If(columnValue has more than one character then "string" else "char")
    If TypeOfCol(column) = "datetime"
      If columnValue isn't a date/time
        TypeOfCol(column) = "string"
  Next
Next
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...