一对多LINQ连接嵌套集合

时间:2013-09-27 22:53:02

标签: c# linq collections

我有一个开发场景,我正在加入Linq的两个馆藏;包含表示元数据的列标题对象的单个列表,以及由Web服务调用产生的kv字典的枚举。我当前可以通过字典枚举迭代(for),并将单个标题列表连接到当前的kv字典而不会出现问题。加入后,我会为每次迭代发出一个精选的字典值数组。

我想要做的是消除for循环,并将单个标题列表直接连接到整个枚举。我理解1对1集合的连接非常好,但是1对N的语法让我望而却步。

详情

我有以下工作方法:

public void GetQueryResults(DataTable outputTable)
{
    var odClient = new ODataClient(UrlBase);
    var odResponse = odClient.FindEntries(CommandText);

    foreach (var row in odResponse)
    {
        var rowValues = OutputFields
            .Join(row, h => h.Key, r => r.Key, 
                (h, r) => new { Header = h, ResultRow = r })
            .Select(r => r.ResultRow.Value);

        outputTable.Rows.Add(rowValues.ToArray());
    }
}

odResponse包含IEnumerable<IDictionary<string, object>>; OutputFields包含IList<QueryField>; .Join生成包含匹配字段元数据(.Header)和响应kv对(.ResultRow)的匿名枚举;最后,.Select发出行消耗的匹配响应值。 OutputField集合如下所示:

class QueryField
{
    public string Key { get; set; }
    public string Label { get; set; }
    public int Order { get; set; }
}

宣称为:

public IList<QueryField> OutputFields { get; private set; }

通过将字段标题集合连接到响应行,我可以从响应中获取所需的列。如果标题键包含{“size”,“shape”,“color”}并且响应键包含{“size”,“mass”,“color”,“longitude”,“latitude”},我将得到一个数组{“size”,“shape”,“color”}的值,其中 shape 为null, mass 经度,以及忽略纬度值。出于本场景的目的,我不关心订购。这一切都有效。

问题

我想要做的是重构此方法以返回值数组行的枚举,并让调用者管理数据的消耗:

public IEnumerable<string[]> GetQueryResults()
{
    var odClient = new ODataClient(UrlBase);
    var odResponse = odClient.FindEntries(CommandText);

    var responseRows = //join OutputFields to each row in odResponse by .Key

    return responseRows;
}

跟进问题

Linq实现的此重构解决方案是否需要立即扫描枚举,还是可以传回惰性结果?重构的目的是改进封装而不用导致冗余的集合扫描。我总是可以构建命令式循环来重新格式化响应数据,但是我想从Linq那里得到的就是闭包。

感谢大家花时间阅读本文;任何建议表示赞赏!

1 个答案:

答案 0 :(得分:0)

我不完全确定你的意思,但是你能说出这样的意思吗?

public IEnumerable<object[]> GetQueryResults()
{

    var odClient = new ODataClient(UrlBase);
    var odResponse = odClient.FindEntries(CommandText);


    // i'd rather you linq here.
    var responseRows = from row in odResponse
                       select new object[] 
                       { 
                           from field in row
                           join outputfield in OutputFields 
                               on field.Key equals outputfield.Key
                           select field.Value 
                       };

    return responseRows;

}

而不是填充DataTable。这将创建一个对象数组,并使用field.Value填充它,其中field.Key存在于outputfields中。整个事情封装在IEnumerable中。 (来自odResponse中的行)

用法:

var responseRows = GetQueryResults2();

foreach(var rowValues in responseRows)
    outputTable.Rows.Add(rowValues);

这里的技巧是,在一个查询中,您迭代列表并在字段上创建子查询,并将子查询结果直接存储在object[]中。 object[]仅在迭代responseRows时创建。这是我认为的第二个问题的答案 - &gt; 懒惰的结果