2016-05-03 67 views
3

私はcsvHelperを使用して.CSVファイルからデータベースを生成しています。 .csvファイルから読み取られるレコードには3つの子クラスがあり、これらの子クラスのいずれかがデータベースに存在する場合と存在しない場合があります。csvHelper動的に子クラスをロードする

私の問題は、csvHelperは存在するすべての子クラスに対して新しいレコードを作成し、代わりにデータベース内の既存のレコードを検索し、存在する場合はこれを使用することです。その結果、子クラステーブルに重複したエントリがたくさん残ってしまいます。

私はユニタリーコンテナを作業単位アプローチで使用しています。ここで

はここ
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; } 
} 

は、私は通常のような、ストリームリソースとしてCSVを使用してCSVファイルにアクセスし、私のクラスマップ

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"); 
    } 
} 

である私のコードです:

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人の審判が作成されます。レスター、エバートン、スティーブ・ダン、アンディ・ホールにはすべて重複が含まれています。つまり、レスターの場合は3チーム、アンディ・ホールの場合は2レフリーのオブジェクトです。

私が使用している.CSVファイルはフラット形式であり、各ゲームの行をしています。ホームチーム、アウェイチーム、審判のためのコラムがあります。他の列もありますが、私が求めている質問の目的のために、他の詳細は無関係です。

csvHelperがゲームレコードを読み込むと、1人の新しい審判と2人の新しいチームが作成されます。 300試合を読んだ後、データベースに300人の審判(250+重複)と600個のチーム(550+重複)があります。理想的には、新しいものを作成する前に、審判とチームをデータベースから検索する必要があります。

ゲームごとに2つのチームが存在するため、CSVファイルに各ラインまたはゲームごとに2つの新しいチームオブジェクトが作成されます。

マッピングを使用してこの作業を行う方法は本当にわかりませんが、援助は歓迎されます。

ありがとうございます。

+0

おそらくこれを達成する別の方法はありますか? – Craig

+0

CSVデータサンプルがありますか?それは他の人が試してみるのにとても役立ちます。 – Ian

+0

例を追加しました。これは単なるフラット形式です。 – Craig

答えて

2

私はCsvHelperライブラリとその内部オブジェクト構築ロジックを見てきました。

巧妙な設定の仕掛けを使用することができますが、私が望むことを実行する最良の方法は非常に簡単であることがわかりました。一意のRefereeTeamを追跡して、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); 
     } 
    } 
+0

あなたのコメントとコードを読んでいたら、これが私が探しているものだと思います。私はこれをできるだけ早く試してみる。ありがとうございました。 – Craig

関連する問題