csvHelper 动态加载子 class
csvHelper dynamically loading child class
我正在使用 csvHelper 从 .CSV 文件填充数据库。从 .csv 文件中读取的任何记录都有 3 个子 classes,这些子 classes 中的任何一个可能已经存在也可能不存在于数据库中。
我的问题是,csvHelper 为存在的每个子 class 创建一个新记录,而它应该在数据库中查找现有记录,如果存在则使用它。结果是,我最终在子 class 表中得到许多重复条目。
我正在使用具有工作单元方法的 Unity 容器。
这是我的代码
public class Game {
public Referee Referee { get; set; }
public Team HomeTeam { get; set; }
public Team AwayTeam { get; set; }
}
public class Referee {
public string Name { get; set; }
}
public class Team {
public string Name { get; set; }
}
这是我的class地图
public sealed class GameMap : CsvClassMap<Game> {
public GameMap () {
References<RefereeMap>(m => m.Referee);
References<HomeTeamMap>(m => m.HomeTeam);
References<AwayTeamMap>(m => m.AwayTeam);
}
}
public sealed class RefereeMap : CsvClassMap<Referee> {
public RefereeMap () {
Map(m => m.Name).Name("RefereeName");
}
}
public sealed class HomeTeamMap : CsvClassMap<Team> {
public HomeTeamMap () {
Map(m => m.Name).Name("TeamName");
}
}
public sealed class AwayTeamMap : CsvClassMap<Team> {
public AwayTeamMap () {
Map(m => m.Name).Name("TeamName");
}
}
我通常会使用 CSV 作为流资源来访问 CSV 文件,例如:
byte[] byteData = webClient.DownloadData(uriAddress);
Stream byteStream = new MemoryStream(byteData);
TextReader reader = new StreamReader(byteStream);
var csv = new CsvReader( reader );
csv.Configuration.RegisterClassMap<GameMap>();
csv.Configuration.RegisterClassMap<RefereeMap>();
csv.Configuration.RegisterClassMap<HomeTeamMap>();
csv.Configuration.RegisterClassMap<AwayTeamMap>();
var records = new List<Game>();
while (csv.Read())
{
records.Add(csv.GetRecord<Game>());
}
...
CSV 文件中的几行通常如下所示
Home, Away, Referee
Leeds, Leicester, Steve Dunn
Derby, Everton, Steve Dunn
Leicester, Man United, Andy Hall
Everton, Leicester, Andy Hall
在这个例子中,总共创建了4场比赛,创建了8支球队和4名裁判。莱斯特、埃弗顿、史蒂夫邓恩和安迪霍尔都包含重复项,这是不正确的,即莱斯特的三个团队对象和安迪霍尔的 2 个裁判对象等。
我正在使用的 .CSV 文件是平面格式,每玩一个游戏都有一行。有主队、客队和裁判的列。还有其他专栏,但就我要问的问题而言,其他细节无关紧要。
当 csvHelper 读取比赛记录时,它会创建 1 个新裁判和 2 个新球队。在阅读了 300 场比赛后,数据库中有 300 名裁判(250+ 重复)和 600 支球队(550+ 重复)。理想情况下,应先从数据库中查找裁判和团队,然后再创建新的。
因为每场比赛有两支球队,所以在 CSV 文件中为每一行或每场比赛创建了两个新的球队对象。
我真的不知道如何使用映射来完成这项工作,欢迎提供帮助。
提前致谢。
我查看了 CsvHelper
库及其内部对象构造逻辑。
虽然您可以使用巧妙的配置技巧,但我发现实现您想要的效果的最佳方法非常简单。您只需跟踪唯一的 Referee
s 和 Team
s 和 link Game
实例到以前的可用实例。
public static class SetExtensions {
public static TValue GetExistingOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> set, TKey key, TValue value) {
TValue existing;
if (set.TryGetValue(key, out existing)) {
return existing;
}
set.Add(key, value);
return value;
}
}
class Program {
static void Main(string[] args) {
Stream inputStream = new MemoryStream();
using (var sw = new StreamWriter(inputStream, Encoding.UTF8, 4096, true)) {
sw.WriteLine("Home, Away, Referee");
sw.WriteLine("Leeds, Leicester, Steve Dunn");
sw.WriteLine("Derby, Everton, Steve Dunn");
sw.WriteLine("Leicester, Man United, Andy Hall");
sw.WriteLine("Everton, Leicester, Andy Hall");
}
inputStream.Position = 0;
TextReader reader = new StreamReader(inputStream);
var csv = new CsvReader(reader);
csv.Configuration.TrimFields = true;
csv.Configuration.TrimHeaders = true;
csv.Configuration.RegisterClassMap<GameMap>(); //You only need to register the "root" map
var referees = new Dictionary<string, Referee>(); //Stores unique referees. You can use the full Referee object as a key if you implement IEquatable<Referee> for Referee
var teams = new Dictionary<string, Team>();
var records = new List<Game>();
while (csv.Read()) {
var record = csv.GetRecord<Game>();
record.Referee = referees.GetExistingOrAdd(record.Referee.Name, record.Referee); //Try to link to existing object
record.HomeTeam = teams.GetExistingOrAdd(record.HomeTeam.Name, record.HomeTeam); //Try to link to existing object
record.AwayTeam = teams.GetExistingOrAdd(record.AwayTeam.Name, record.AwayTeam); //Try to link to existing object
records.Add(record);
}
}
我正在使用 csvHelper 从 .CSV 文件填充数据库。从 .csv 文件中读取的任何记录都有 3 个子 classes,这些子 classes 中的任何一个可能已经存在也可能不存在于数据库中。
我的问题是,csvHelper 为存在的每个子 class 创建一个新记录,而它应该在数据库中查找现有记录,如果存在则使用它。结果是,我最终在子 class 表中得到许多重复条目。
我正在使用具有工作单元方法的 Unity 容器。
这是我的代码
public class Game {
public Referee Referee { get; set; }
public Team HomeTeam { get; set; }
public Team AwayTeam { get; set; }
}
public class Referee {
public string Name { get; set; }
}
public class Team {
public string Name { get; set; }
}
这是我的class地图
public sealed class GameMap : CsvClassMap<Game> {
public GameMap () {
References<RefereeMap>(m => m.Referee);
References<HomeTeamMap>(m => m.HomeTeam);
References<AwayTeamMap>(m => m.AwayTeam);
}
}
public sealed class RefereeMap : CsvClassMap<Referee> {
public RefereeMap () {
Map(m => m.Name).Name("RefereeName");
}
}
public sealed class HomeTeamMap : CsvClassMap<Team> {
public HomeTeamMap () {
Map(m => m.Name).Name("TeamName");
}
}
public sealed class AwayTeamMap : CsvClassMap<Team> {
public AwayTeamMap () {
Map(m => m.Name).Name("TeamName");
}
}
我通常会使用 CSV 作为流资源来访问 CSV 文件,例如:
byte[] byteData = webClient.DownloadData(uriAddress);
Stream byteStream = new MemoryStream(byteData);
TextReader reader = new StreamReader(byteStream);
var csv = new CsvReader( reader );
csv.Configuration.RegisterClassMap<GameMap>();
csv.Configuration.RegisterClassMap<RefereeMap>();
csv.Configuration.RegisterClassMap<HomeTeamMap>();
csv.Configuration.RegisterClassMap<AwayTeamMap>();
var records = new List<Game>();
while (csv.Read())
{
records.Add(csv.GetRecord<Game>());
}
...
CSV 文件中的几行通常如下所示
Home, Away, Referee
Leeds, Leicester, Steve Dunn
Derby, Everton, Steve Dunn
Leicester, Man United, Andy Hall
Everton, Leicester, Andy Hall
在这个例子中,总共创建了4场比赛,创建了8支球队和4名裁判。莱斯特、埃弗顿、史蒂夫邓恩和安迪霍尔都包含重复项,这是不正确的,即莱斯特的三个团队对象和安迪霍尔的 2 个裁判对象等。
我正在使用的 .CSV 文件是平面格式,每玩一个游戏都有一行。有主队、客队和裁判的列。还有其他专栏,但就我要问的问题而言,其他细节无关紧要。
当 csvHelper 读取比赛记录时,它会创建 1 个新裁判和 2 个新球队。在阅读了 300 场比赛后,数据库中有 300 名裁判(250+ 重复)和 600 支球队(550+ 重复)。理想情况下,应先从数据库中查找裁判和团队,然后再创建新的。
因为每场比赛有两支球队,所以在 CSV 文件中为每一行或每场比赛创建了两个新的球队对象。
我真的不知道如何使用映射来完成这项工作,欢迎提供帮助。
提前致谢。
我查看了 CsvHelper
库及其内部对象构造逻辑。
虽然您可以使用巧妙的配置技巧,但我发现实现您想要的效果的最佳方法非常简单。您只需跟踪唯一的 Referee
s 和 Team
s 和 link Game
实例到以前的可用实例。
public static class SetExtensions {
public static TValue GetExistingOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> set, TKey key, TValue value) {
TValue existing;
if (set.TryGetValue(key, out existing)) {
return existing;
}
set.Add(key, value);
return value;
}
}
class Program {
static void Main(string[] args) {
Stream inputStream = new MemoryStream();
using (var sw = new StreamWriter(inputStream, Encoding.UTF8, 4096, true)) {
sw.WriteLine("Home, Away, Referee");
sw.WriteLine("Leeds, Leicester, Steve Dunn");
sw.WriteLine("Derby, Everton, Steve Dunn");
sw.WriteLine("Leicester, Man United, Andy Hall");
sw.WriteLine("Everton, Leicester, Andy Hall");
}
inputStream.Position = 0;
TextReader reader = new StreamReader(inputStream);
var csv = new CsvReader(reader);
csv.Configuration.TrimFields = true;
csv.Configuration.TrimHeaders = true;
csv.Configuration.RegisterClassMap<GameMap>(); //You only need to register the "root" map
var referees = new Dictionary<string, Referee>(); //Stores unique referees. You can use the full Referee object as a key if you implement IEquatable<Referee> for Referee
var teams = new Dictionary<string, Team>();
var records = new List<Game>();
while (csv.Read()) {
var record = csv.GetRecord<Game>();
record.Referee = referees.GetExistingOrAdd(record.Referee.Name, record.Referee); //Try to link to existing object
record.HomeTeam = teams.GetExistingOrAdd(record.HomeTeam.Name, record.HomeTeam); //Try to link to existing object
record.AwayTeam = teams.GetExistingOrAdd(record.AwayTeam.Name, record.AwayTeam); //Try to link to existing object
records.Add(record);
}
}