CsvHelper - 将多个相关列读入对象列表
CsvHelper - Read multiple related columns into a list of objects
我有这样的 CSV:(注意:实际的 csv 每个重复列有 5 个,而不是只有 2 个)
Id Name Diagnosis 1 Diagnosis 2 Drug 1 Drug 2 How Taken 1 How Taken 2
== ==== =========== =========== ====== ====== =========== ===========
1 One F23 F25 D1 D55 Oral Inject
2 Two F30 D5 D7 Inject Inhale
我正在使用 CsvHelper 将其映射到我的 POCO 对象中,如下所示:
public class Episode {
public int Id {get; set;}
public string Name {get; set;}
public IList<string> Diagnoses {get; set;}
public IList<Drug> Drugs { get; set;}
}
public class Drug {
public int Id {get; set;}
public string Name {get; set;}
public string AdministrationMethod {get; set;}
}
我看过一些关于使用 CsvHelper 映射到 IEnumerable 的参考资料,但没有关于它的正式文档。
有什么办法可以:
- 将诊断 1、诊断 2 等映射到
IList<string> Diagnoses
属性?
- 将 [药物 x, 如何服用 x] 对映射到
IList<Drug> Drugs
属性?
以下是我所知道的最接近的内容(绝对行不通,但试图帮助给出我所追求的概念)。
void Main()
{
using (var reader = new StreamReader("path\to\file.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.RegisterClassMap<EpisodeMap>();
var records = csv.GetRecords<EpisodeMap>();
}
}
public EpisodeMap : ClassMap<Episode>{
public EpisodeMap(){
Map(m => m.Name).Name("Name");
Map(m => m.Diagnoses).Name("Diagnosis").Index(5); //Unsure how to indicate appropriate name "Diagnosis {index}"
References<DrugMap>(m => m.Drugs).Index(5); //?? Not sure if something like this is possible
}
}
public DrugMap : ClassMap<Drug> {
public DrugMap() {
Map(m => m.Name).Name("Drug");
Map(m => m.AdministrationMethod).Name("How Taken");
}
不幸的是 Index()
只适用于像 IEnumerable<string>
这样的简单 IEnumerables。对于更复杂的 objects,您将需要使用 ConvertUsing()
,利用列的名称或索引。 Name()
应该适用于 Diagnosis
,但出于某种原因,如果标题列的名称与 属性 Diagnoses
.[=19 相同,我只能让它工作=]
您还可以使用 ConvertUsing()
使 Diagnosis
标题正常工作。
public class Program
{
public static void Main(string[] args)
{
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader = new StreamReader(stream))
using (CsvReader csv = new CsvReader(reader, new Configuration()))
{
writer.WriteLine("Id,Name,Diagnoses 1,Diagnoses 2,Drug 1,Drug 2,How Taken 1,How Taken 2");
writer.WriteLine("1,One,F23,F25,D1,D55,Oral,Inject");
writer.WriteLine("2,Two,F30,,D5,D7,Inject,Inhale");
writer.Flush();
stream.Position = 0;
reader.BaseStream.Position = 0;
csv.Configuration.RegisterClassMap<EpisodeMap>();
csv.Configuration.PrepareHeaderForMatch = (header, index) => Regex.Replace(header, " ", string.Empty);
var records = csv.GetRecords<Episode>().ToList();
}
Console.ReadKey();
}
}
public class EpisodeMap : ClassMap<Episode>
{
public EpisodeMap()
{
Map(m => m.Id);
Map(m => m.Name);
Map(m => m.Diagnoses).Index(2,3); //Unsure how to indicate appropriate name "Diagnosis {index}"
Map(m => m.Drugs).ConvertUsing(row =>
{
return new List<Drug>
{
new Drug { Name = row["Drug1"], AdministrationMethod = row["HowTaken1"] },
new Drug { Name = row["Drug2"], AdministrationMethod = row["HowTaken2"]}
};
});
}
}
我有这样的 CSV:(注意:实际的 csv 每个重复列有 5 个,而不是只有 2 个)
Id Name Diagnosis 1 Diagnosis 2 Drug 1 Drug 2 How Taken 1 How Taken 2
== ==== =========== =========== ====== ====== =========== ===========
1 One F23 F25 D1 D55 Oral Inject
2 Two F30 D5 D7 Inject Inhale
我正在使用 CsvHelper 将其映射到我的 POCO 对象中,如下所示:
public class Episode {
public int Id {get; set;}
public string Name {get; set;}
public IList<string> Diagnoses {get; set;}
public IList<Drug> Drugs { get; set;}
}
public class Drug {
public int Id {get; set;}
public string Name {get; set;}
public string AdministrationMethod {get; set;}
}
我看过一些关于使用 CsvHelper 映射到 IEnumerable 的参考资料,但没有关于它的正式文档。
有什么办法可以:
- 将诊断 1、诊断 2 等映射到
IList<string> Diagnoses
属性? - 将 [药物 x, 如何服用 x] 对映射到
IList<Drug> Drugs
属性?
以下是我所知道的最接近的内容(绝对行不通,但试图帮助给出我所追求的概念)。
void Main()
{
using (var reader = new StreamReader("path\to\file.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.RegisterClassMap<EpisodeMap>();
var records = csv.GetRecords<EpisodeMap>();
}
}
public EpisodeMap : ClassMap<Episode>{
public EpisodeMap(){
Map(m => m.Name).Name("Name");
Map(m => m.Diagnoses).Name("Diagnosis").Index(5); //Unsure how to indicate appropriate name "Diagnosis {index}"
References<DrugMap>(m => m.Drugs).Index(5); //?? Not sure if something like this is possible
}
}
public DrugMap : ClassMap<Drug> {
public DrugMap() {
Map(m => m.Name).Name("Drug");
Map(m => m.AdministrationMethod).Name("How Taken");
}
不幸的是 Index()
只适用于像 IEnumerable<string>
这样的简单 IEnumerables。对于更复杂的 objects,您将需要使用 ConvertUsing()
,利用列的名称或索引。 Name()
应该适用于 Diagnosis
,但出于某种原因,如果标题列的名称与 属性 Diagnoses
.[=19 相同,我只能让它工作=]
您还可以使用 ConvertUsing()
使 Diagnosis
标题正常工作。
public class Program
{
public static void Main(string[] args)
{
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader = new StreamReader(stream))
using (CsvReader csv = new CsvReader(reader, new Configuration()))
{
writer.WriteLine("Id,Name,Diagnoses 1,Diagnoses 2,Drug 1,Drug 2,How Taken 1,How Taken 2");
writer.WriteLine("1,One,F23,F25,D1,D55,Oral,Inject");
writer.WriteLine("2,Two,F30,,D5,D7,Inject,Inhale");
writer.Flush();
stream.Position = 0;
reader.BaseStream.Position = 0;
csv.Configuration.RegisterClassMap<EpisodeMap>();
csv.Configuration.PrepareHeaderForMatch = (header, index) => Regex.Replace(header, " ", string.Empty);
var records = csv.GetRecords<Episode>().ToList();
}
Console.ReadKey();
}
}
public class EpisodeMap : ClassMap<Episode>
{
public EpisodeMap()
{
Map(m => m.Id);
Map(m => m.Name);
Map(m => m.Diagnoses).Index(2,3); //Unsure how to indicate appropriate name "Diagnosis {index}"
Map(m => m.Drugs).ConvertUsing(row =>
{
return new List<Drug>
{
new Drug { Name = row["Drug1"], AdministrationMethod = row["HowTaken1"] },
new Drug { Name = row["Drug2"], AdministrationMethod = row["HowTaken2"]}
};
});
}
}