2008-12-16 22 views
2

給定一個DataSet,我將DataTables [1-n]加入DataTable [0]。我創建了一個與方法的簽名如下:LINQ Group使用兩個DataTable加入innerKeySelector/outerKeySeletor問題

public DataTable LeftJoin(DataSet ds, params JoinKey[] JoinKey) 

注:

  • 返回類型是一個DataTable,這是得到的左加入。
  • DataSet ds是用於加入的DataTables的集合。
  • JoinKey是一個具有兩個公共屬性的對象:Type DataType和string Name。此集合包含要在聯接中使用的每個字段的類型/名稱。

以下是兩個片段(片段1片段2)片段1個正常工作。唯一的問題是GroupJoin的第二個和第三個參數是硬編碼的:

// hard-coded: 
br => new         
{         
    zip = br.Field<string>("ZipCode"),         
    store =br.Field<double>"StoreID") 
},         
jr => new         
{         
    zip = jr.Field<string>("ZipCode"),         
    store = jr.Field<double>("StoreID")         
} 

以上是不可取的。相反,我想用我的「JoinKey」對象來動態設置我想加入的字段(即ZipCode和StoreID)。我有企圖這在片段2。然而,首先,請參閱片段1.

片段1(工作,硬編碼)

var dtBase = ds.Tables[0].AsEnumerable(); 
for (int i = 1; i < ds.Tables.Count; i++) 
{ 
    var query = dtBase.GroupJoin(ds.Tables[i].AsEnumerable(), 
           br => new 
           { 
            zip = br.Field<string>("ZipCode"), 
            store = br.Field<double>("StoreID") 
           }, 
           jr => new 
           { 
            zip = jr.Field<string>("ZipCode"), 
            store = jr.Field<double>("StoreID") 
           }, 
           (baseRow, joinRow) => joinRow.DefaultIfEmpty() 
            .Select(row => new 
            { 
             flatRow = baseRow.ItemArray.Concat((row == null) ? new object[ds.Tables[i].Columns.Count] : row.ItemArray).ToArray() 
            }) 
         ).SelectMany(s => s); 



    [... create a DataTable with the resulting left join, etc. ...] 
} 

注:變量, 「flatRow」,存儲左接合數據的對象陣列;它稍後會在方法中添加到DataRowCollection中(未顯示)。

片段2(不工作;拋出沒有任何錯誤,但是)

var dtBase = ds.Tables[0].AsEnumerable(); 
for (int i = 1; i < ds.Tables.Count; i++) 
{ 
    var query = dtBase.GroupJoin(ds.Tables[i].AsEnumerable(), 
           or => KeySelector(or, JoinKey), 
           ir => KeySelector(ir, JoinKey), 
           (baseRow, joinRows) => joinRows.DefaultIfEmpty() 
            .Select(joinRow => new 
            { 
             flatRow = baseRow.ItemArray.Concat((joinRow == null) ? new object[ds.Tables[i].Columns.Count] : joinRow.ItemArray).ToArray() 
            }) 
           ) 
         .SelectMany(s => s); 

    [... create a DataTable with the resulting left join, etc. ...] 
} 

下面是上面所用的的KeySelectors功能(請參閱內嵌註釋):

private IEnumerable KeySelector(DataRow dr, params JoinKey[] JoinKey) 
{ 
    List<object> gl = new List<object>(); 
    foreach (JoinKey jk in JoinKey) 
    { 
    // note that I did try to mimic the 'hard-coded' approach from Snippet 1: 
    // this does not work: 
    // gl.Add(dr.Field<jk.DataType>(jk.Name)); --> it does not like <jk.DataType> 

    // I 'hacked' around it by using the following: 

    gl.Add(dr[dr.Table.Columns.IndexOf(jk.Name)]); 
    } 
    return gl; 
} 

代碼段2只返回來自DataTable [0]的數據。 DataTable [1-n](如果存在的話)中的數據都沒有連接到變量「flatRow」中。有趣的是,我確實得到了數組中正確數量的元素。我知道這與KeySelector方法有關,但(顯然)我不知道問題是什麼。

如果有人需要更多信息,請讓我知道。你的幫助是極大的讚賞...

感謝,
泰勒

是立即發生的是,在一個關鍵的使用 double是自找麻煩

回答

1

一件事;浮點數的平等比較是出乎意料的。不過,我仍在尋找。

我認爲這裏的主要問題是根據內容在列表中根本沒有自動的相等性;你正在返回不同的列表(從KeySelector),所以他們根本不會相等。您可能能夠提供自定義比較器...

這是混亂的,但得到的東西返回

class SetComparer : IEqualityComparer<IEnumerable> 
    { 

     public readonly static SetComparer Default = new SetComparer(); 

     public bool Equals(IEnumerable x, IEnumerable y) 
     { 
      return Enumerable.SequenceEqual(x.Cast<object>(), y.Cast<object>()); 
     } 

     public int GetHashCode(IEnumerable data) 
     { 
      int hash = 0; 
      foreach (object obj in data) 
      { 
       if (obj != null) 
       { 
        hash = hash * 7 + 13 * obj.GetHashCode(); 
       } 
      } 
      return hash; 
     } 
    } 

又通SetComparer.Default在作爲最後(可選)對Arg的GroupJoin

更新:發現我的錯誤 - 我想borked GetHashCode();固定。

你可能也可以通過在運行時創建一個表達式來作爲比較器(並且只是將該行本身作爲關鍵字)來做類似的事情,但這更復雜。