我有以下代码,它采用CSV并写入控制台:
using (CsvReader csv = new CsvReader(
new StreamReader("data.csv"), true))
{
// missing fields will not throw an exception,
// but will instead be treated as if there was a null value
csv.MissingFieldAction = MissingFieldAction.ReplaceByNull;
// to replace by "" instead, then use the following action:
//csv.MissingFieldAction = MissingFieldAction.ReplaceByEmpty;
int fieldCount = csv.FieldCount;
string[] headers = csv.GetFieldHeaders();
while (csv.ReadNextRecord())
{
for (int i = 0; i < fieldCount; i++)
Console.Write(string.Format("{0} = {1};",
headers[i],
csv[i] == null ? "MISSING" : csv[i]));
Console.WriteLine();
}
}
CSV文件有7个标题,我的SQL表中有7列。
将每个csv[i]
和每个列的行写入一行然后移到下一行的最佳方法是什么?
我尝试将ccsv[i]
添加到字符串数组中,但这不起作用。
我也尝试了以下内容:
SqlCommand sql = new SqlCommand("INSERT INTO table1 [" + csv[i] + "]", mysqlconnectionstring);
sql.ExecuteNonQuery();
我的表格(table1
)是这样的:
name address city zipcode phone fax device
答案 0 :(得分:1)
你的问题很简单,但我会更进一步,让你知道一个更好的方法来处理这个问题。
当您遇到问题时,请务必将其分解为零件并将每个零件应用于每个方法中。例如,在您的情况下:
你甚至可以添加验证到文件中(想象你的文件在一行或多行中甚至没有7个字段......)以及下面的例子,只有你的文件永远不会传递大约500行,就好像它通常你应该考虑使用一个SQL语句将你的文件直接存入数据库,它被称为bulk insert
1 - 从文件中读取:
我会使用List<string>
来保存行条目,并且我总是使用StreamReader
来读取文本文件。
using (StreamReader sr = File.OpenText(this.CsvPath))
{
while ((line = sr.ReadLine()) != null)
{
splittedLine = line.Split(new string[] { this.Separator }, StringSplitOptions.None);
if (iLine == 0 && this.HasHeader)
// header line
this.Header = splittedLine;
else
this.Lines.Add(splittedLine);
iLine++;
}
}
2 - 生成sql
foreach (var line in this.Lines)
{
string entries = string.Concat("'", string.Join("','", line))
.TrimEnd('\'').TrimEnd(','); // remove last ",'"
this.Query.Add(string.Format(this.LineTemplate, entries));
}
3 - 运行查询
SqlCommand sql = new SqlCommand(string.Join("", query), mysqlconnectionstring);
sql.ExecuteNonQuery();
有一些乐趣我最终做了解决方案,你可以在这里下载,输出是:
<强> The code can be found here 即可。它需要更多的调整,但我会留给其他人。解决方案用C#编写,VS 2013。
ExtractCsvIntoSql
类如下:
public class ExtractCsvIntoSql
{
private string CsvPath, Separator;
private bool HasHeader;
private List<string[]> Lines;
private List<string> Query;
/// <summary>
/// Header content of the CSV File
/// </summary>
public string[] Header { get; private set; }
/// <summary>
/// Template to be used in each INSERT Query statement
/// </summary>
public string LineTemplate { get; set; }
public ExtractCsvIntoSql(string csvPath, string separator, bool hasHeader = false)
{
this.CsvPath = csvPath;
this.Separator = separator;
this.HasHeader = hasHeader;
this.Lines = new List<string[]>();
// you can also set this
this.LineTemplate = "INSERT INTO [table1] SELECT ({0});";
}
/// <summary>
/// Generates the SQL Query
/// </summary>
/// <returns></returns>
public List<string> Generate()
{
if(this.CsvPath == null)
throw new ArgumentException("CSV Path can't be empty");
// extract csv into object
Extract();
// generate sql query
GenerateQuery();
return this.Query;
}
private void Extract()
{
string line;
string[] splittedLine;
int iLine = 0;
try
{
using (StreamReader sr = File.OpenText(this.CsvPath))
{
while ((line = sr.ReadLine()) != null)
{
splittedLine = line.Split(new string[] { this.Separator }, StringSplitOptions.None);
if (iLine == 0 && this.HasHeader)
// header line
this.Header = splittedLine;
else
this.Lines.Add(splittedLine);
iLine++;
}
}
}
catch (Exception ex)
{
if(ex.InnerException != null)
while (ex.InnerException != null)
ex = ex.InnerException;
throw ex;
}
// Lines will have all rows and each row, the column entry
}
private void GenerateQuery()
{
foreach (var line in this.Lines)
{
string entries = string.Concat("'", string.Join("','", line))
.TrimEnd('\'').TrimEnd(','); // remove last ",'"
this.Query.Add(string.Format(this.LineTemplate, entries));
}
}
}
您可以将其运行为:
class Program
{
static void Main(string[] args)
{
string file = Ask("What is the CSV file path? (full path)");
string separator = Ask("What is the current separator? (; or ,)");
var extract = new ExtractCsvIntoSql(file, separator);
var sql = extract.Generate();
Output(sql);
}
private static void Output(IEnumerable<string> sql)
{
foreach(var query in sql)
Console.WriteLine(query);
Console.WriteLine("*******************************************");
Console.Write("END ");
Console.ReadLine();
}
private static string Ask(string question)
{
Console.WriteLine("*******************************************");
Console.WriteLine(question);
Console.Write("= ");
return Console.ReadLine();
}
}
答案 1 :(得分:1)
通常我喜欢更通用,所以我会尝试解释我不时使用的非常基本的流程:
我不喜欢硬编码的态度,所以即使你的代码能够运行,它也会专门用于一种类型。我更喜欢简单的反思,首先要了解DTO是什么,然后了解我应该使用哪个存储库来操作它:
例如:
public class ImportProvider
{
private readonly string _path;
private readonly ObjectResolver _objectResolver;
public ImportProvider(string path)
{
_path = path;
_objectResolver = new ObjectResolver();
}
public void Import()
{
var filePaths = Directory.GetFiles(_path, "*.csv");
foreach (var filePath in filePaths)
{
var fileName = Path.GetFileName(filePath);
var className = fileName.Remove(fileName.Length-4);
using (var reader = new CsvFileReader(filePath))
{
var row = new CsvRow();
var repository = (DaoBase)_objectResolver.Resolve("DAL.Repository", className + "Dao");
while (reader.ReadRow(row))
{
var dtoInstance = (DtoBase)_objectResolver.Resolve("DAL.DTO", className + "Dto");
dtoInstance.FillInstance(row.ToArray());
repository.Save(dtoInstance);
}
}
}
}
}
上面是一个负责导入数据的非常基础的类。不过这段代码如何解析CSV文件(CsvFileReader),重要的部分是那个&#34; CsvRow&#34;是一个简单的列表。
以下是ObjectResolver的实现:
public class ObjectResolver
{
private readonly Assembly _myDal;
public ObjectResolver()
{
_myDal = Assembly.Load("DAL");
}
public object Resolve(string nameSpace, string name)
{
var myLoadClass = _myDal.GetType(nameSpace + "." + name);
return Activator.CreateInstance(myLoadClass);
}
}
我的想法是简单地遵循命名对话,在我的情况下是使用&#34; Dto&#34;用于反映实例的后缀,以及&#34; Dao&#34;用于反映负责任的dao的后缀。 Dto或Dao的全名可以从csv名称或标题中获取(如您所愿)
下一步是填写Dto,每个dto或实现以下简单摘要:
public abstract class DtoBase
{
public abstract void FillInstance(params string[] parameters);
}
因为每个Dto&#34;都知道&#34;他的结构(就像你知道在数据库中创建一个合适的表),它可以轻松实现FillInstanceMethod,这里有一个简单的Dto示例:
public class ProductDto : DtoBase
{
public int ProductId { get; set; }
public double Weight { get; set; }
public int FamilyId { get; set; }
public override void FillInstance(params string[] parameters)
{
ProductId = int.Parse(parameters[0]);
Weight = double.Parse(parameters[1]);
FamilyId = int.Parse(parameters[2]);
}
}
在您的Dto填充数据后,您应找到适当的Dao来处理它 这基本上发生在Import()方法的这一行的反射中:
var repository = (DaoBase)_objectResolver.Resolve("DAL.Repository", className + "Dao");
在我的例子中,Dao实现了一个抽象基类 - 但它与你的问题没有关系,你的DaoBase可以是一个带有单个Save()方法的简单抽象。 通过这种方式,你有一个专门的Dao to CRUD你的Dto - 每个Dao只知道如何为其相关的Dto保存。以下是ProductDto的相应ProductDao:
public class ProductDao : DaoBase
{
private const string InsertProductQuery = @"SET foreign_key_checks = 0;
Insert into product (productID, weight, familyID)
VALUES (@productId, @weight, @familyId);
SET foreign_key_checks = 1;";
public override void Save(DtoBase dto)
{
var productToSave = dto as ProductDto;
var saveproductCommand = GetDbCommand(InsertProductQuery);
if (productToSave != null)
{
saveproductCommand.Parameters.Add(CreateParameter("@productId", productToSave.ProductId));
saveproductCommand.Parameters.Add(CreateParameter("@weight", productToSave.Weight));
saveproductCommand.Parameters.Add(CreateParameter("@familyId", productToSave.FamilyId));
ExecuteNonQuery(ref saveproductCommand);
}
}
}
请忽略CreateParameter()方法,因为它是基类的抽象。你可以使用CreateSqlParameter或CreateDataParameter等。
请注意,这是一个真正天真的实施 - 你可以根据自己的需要轻松改造它。
答案 2 :(得分:0)
从你问题的第一印象我想你会有大量的记录(超过lacs)。如果是,我会认为SQL批量复制一个选项。如果记录会减少单个记录。插入。插入不起作用的原因是你没有提供表的所有列,也有一些语法错误。