我必须编写一个可怕的接口,将数据从我们的旧应用程序中的数百个数据文件导入到一个新数据库中,该应用程序对所有内容都进行了硬编码(显示的数据类似于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; }
}
我最担心的是,我不想错误地解释其中一个输入(比如将布尔值转换为char)。
我还在寻找一种方法来比较MyParameter
的新实例(即,如果它小于一种类型,请尝试另一种类型)。
看到一些很酷的新表情来生成这个的奖励积分!
给定一些抽象的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
中的数据(在将表本身添加到数据库之后)。
我认为问题不在代码中,这似乎是一种知道的方式,因为你总是以字符串的形式接收params,我认为你可以更好地尝试,但在数据提取步骤中,
也许使用头列,您可以将它们"解析"为一种类型。。
并尝试
Convert.ChangeType(yourValue, typeof(string, double,etc))
这个伪代码怎么样?我认为这对你来说应该足够快了。这是非常伪的,所以"string"、"char"等只是枚举值或其他任何您喜欢的值的占位符。
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