给定一个DataSet,我将DataTables [1-n]连接到DataTable [0]。我创建了一个带签名的方法,如下所示:
public DataTable LeftJoin(DataSet ds, params JoinKey[] JoinKey)
注意:
以下是两个代码段( Snippet 1 和 Snippet 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)。我在 Snippet 2 中尝试。不过,首先请参阅Snippet 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. ...]
}
以上是上面使用的 KeySelector 函数(请参阅内联注释):
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;
}
Snippet 2 仅返回DataTable [0]中的数据。来自DataTable [1-n](如果存在)的数据都不会连接到变量“flatRow”中。有趣的是,我确实得到了数组中正确数量的元素。我知道这与KeySelector方法有关,但(显然)我不知道问题是什么。
如果有人需要其他信息,请与我们联系。非常感谢您的帮助......
谢谢,
泰勒
答案 0 :(得分:1)
立即发生的一件事是在密钥中使用double
会产生麻烦;浮点数的相等比较是众所周知的。不过我还在寻找。
我认为这里的主要问题是基于内容的列表上没有自动相等;你正在返回不同的列表(来自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
。
更新:发现我的错误 - 我已经开始GetHashCode()
;固定的。
你可能也可以通过在运行时构建一个表达式来用作比较器(并且只是将行本身作为键返回)来做类似的事情,但这更复杂。