2017-07-13 12 views
2

Linqを使用して2つのデータテーブルを比較しようとしています。非常に単純なテーブルで、1つの列だけですが、約44,000行あります。私は、次を使用しますが、ときに私はそれをトレース、もし(dr.Any())、それが取得するときに、それだけでそこに座って、次の行、または例外、実行されることはありません:Linq Any()タイムアウト

public static DataTable GetTableDiff(DataTable dt1, DataTable dt2) 
{ 
    DataTable dtDiff = new DataTable(); 
    try 
    { 
     var dr = from r in dt1.AsEnumerable() where !dt2.AsEnumerable().Any(r2 => r["FacilityID"].ToString().Trim().ToLower() == r2["FacilityID"].ToString().Trim().ToLower()) select r; 

     if (dr.Any()) 
      dtDiff = dr.CopyToDataTable(); 
    } 
    catch (Exception ex) 
    { 
    } 
    return dtDiff; 
} 

私は最大要求の長さを設定しますweb.configで問題はないが変更はないことを確認してください。

<system.web> 
    <compilation debug="true" targetFramework="4.5" /> 
    <httpRuntime targetFramework="4.5" maxRequestLength="1048576" /> 

44,000行が大きすぎるとは思われません。

+3

[maxRequestLength](https://msdn.microsoft.com/en-us/library/e1f13641%28v=vs。 85%29.aspx) '入力ストリームバッファリングの制限値をKBで指定します。この制限は、例えば、大規模なファイルをサーバに投稿したユーザによるサービス拒否攻撃を防ぐために使用できます。これは、リクエストサイズに関連し、Linqクエリには関連しません。 –

答えて

4

代わりにO(あなたはDT2のすべての行をスキャンしているDT1に現在の行ごと)(N1 * N2)検索やってのテーブルO(N1 + N2)参加:では

var diff = from r1 in dt1.AsEnumerable() 
      join r2 in dt2.AsEnumerable() 
       on r1.Field<string>("FacilityID").Trim().ToLower() 
       equals r2.Field<string>("FacilityID").Trim().ToLower() into g 
      where !g.Any() // get only rows which do not have joined rows from dt2 
      select r1; 

はあなたにもなります参加各鍵(施設ID)を1回だけ計算します。


別のオプションは、単純な行の比較子を作成している:

public class FacilityIdComparer : IEqualityComparer<DataRow> 
{ 
    public bool Equals(DataRow x, DataRow y) => GetFacilityID(x) == GetFacilityID(y); 
    public int GetHashCode(DataRow row) => GetFacilityID(row)?.GetHashCode() ?? 0; 
    private string GetFacilityID(DataRow row) 
     => row.Field<string>("FacilityID")?.Trim().ToLower(); 
} 

は、その後、新しい行を取得することはLINQ Except方法で1つのライナーです:

var diff = dt2.AsEnumerable().Except(dt1.AsEnumerable(), new FacilityIdComparer()); 

、それは同様に検索する交差点のために動作します

+1

ありがとうございます。あなたのソリューションとTimの両方が同じように機能しましたが、それが最初だったので私は答えとしてあなたのマークを付けました。 – NoBullMan

3

私は別のより軽量のアプローチを使用しますあなただけの1つの表から行を取り、あなたが新しいFacilityIdを持つもののみたいので:

public static DataTable GetTableDiff(DataTable dtNew, DataTable dtOld) 
{ 
    DataTable dtDiff = dtNew.Clone(); // no data only columns and constraints 
    var oldFacilityIds = dtOld.AsEnumerable().Select(r => r.Field<string>("FacilityID").Trim()); 
    var oldFacilityIDSet = new HashSet<string>(oldFacilityIds, StringComparer.CurrentCultureIgnoreCase); 

    var newRows = dtNew.AsEnumerable() 
     .Where(r => !oldFacilityIDSet.Contains(r.Field<string>("FacilityID").Trim())); 

    foreach (DataRow row in newRows) 
     dtDiff.ImportRow(row); 

    return dtDiff; 
} 
関連する問題