简体   繁体   English

如何将多个linq查询组合到一个结果集中?

[英]How do I combine multiple linq queries into one results set?

I have a multi-select checkbox. 我有一个多选复选框。 Depending on which one is checked, I want to combine the results into a single query. 根据检查的是哪一个,我想将结果合并到一个查询中。 Sort of like: 有点像:

if (Checkbox1.Checked)
{
    var query1 = from t in table1 ...
}

if (Checkbox2.Checked)
{
    var query2 = from t in table2 ...
}

DataGridView1.DataSource = query1.Union(query2); // obviously doesnt
      // work since query1 and query2 are not defined in this scope.

Any idea how to combine these selectively? 知道如何有选择地组合这些吗?

Assuming the queries are of the same type, you could define the queries outside of the conditional statements. 假设查询类型相同,您可以在条件语句之外定义查询。

First, a helper method that creates an empty enumerable of the same type as the parameter: 首先,一个辅助方法,它创建一个与参数相同类型的空可枚举:

static IEnumerable<T> CreateEmptyEnumerable<T>(IEnumerable<T> templateQuery)
{
    return Enumerable.Empty<T>();
}

Then, the new code: 然后,新代码:

var query1 = from t in table1 ...
var query2 = from t in table2 ...
var finalQuery = CreateEmptyEnumerable(query1);

if (Checkbox1.Checked)
{
    finalQuery = query1;
}

if (Checkbox2.Checked)
{
    finalQuery = finalQuery.Union(query2);
}

DataGridView1.DataSource = finalQuery.ToList(); // to avoid re-enumeration

This performs just fine because the queries aren't actually executed until they're enumerated over, as in the call to ToList() . 这样做很好,因为查询在枚举之前不会被实际执行,就像调用ToList()

Using Rx you can do something like this: 使用Rx你可以这样做:

public partial class _Default : System.Web.UI.Page
{
    IEnumerable<int> table1;
    IEnumerable<int> table2;

    protected void Page_Load(object sender, EventArgs e)
    {
        table1 = Enumerable.Range(0, 10);
        table2 = Enumerable.Range(10, 10);
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        var query = 
            Observable.If(() => CheckBox1.Checked,
                (from t in table1 select t).ToObservable(), Observable.Empty<int>())
            .Concat(
                Observable.If(() => CheckBox2.Checked,
                (from t in table2 select t).ToObservable(), Observable.Empty<int>())
            );

        query.Subscribe(i => Response.Write(i));
    }
}

If you would not use var but a known type, then you could initialize query1 and query2 via 如果您不使用var但已知类型,则可以通过初始化query1和query2

Enumerable.Empty<T> in case of the checkbox not being checked. 如果未选中复选框,则为Enumerable.Empty<T>

I just tried this in a console application, as I was curious, and it just worked.... 我只是在一个控制台应用程序中尝试过这个,因为我很好奇,它只是起作用....

class Program
{
    private class Data1
    {
        public int Code1 { get; set; }
        public string Value1 { get; set; }
    }

    private class Data2
    {
        public int Code2 { get; set; }
        public string Value2 { get; set; }
    }

    static void Main(string[] args)
    {
        var data1 = new[] { new Data1 { Code1 = 1, Value1 = "one" }, new Data1 { Code1 = 2, Value1 = "two" }, new Data1 { Code1 = 3, Value1 = "three" } };
        var data2 = new[] { new Data2 { Code2 = 101, Value2 = "aaa" }, new Data2 { Code2 = 102, Value2 = "bbb" }, new Data2 { Code2 = 103, Value2 = "ccc" } };

        var query1 = from d1 in data1 select new { code = d1.Code1, text = d1.Value1 };
        var query2 = from d2 in data2 select new { code = d2.Code2, text = d2.Value2 };

        var datasource = query1.Union(query2);

        foreach (var d in datasource)
        {
            Console.WriteLine(d);
        }
    }
}

However, if I change the fieldnames in the anonymous types to be different I get a compiler error, so it looks like the key is to have the names the same in your anonymous types. 但是,如果我将匿名类型中的字段名更改为不同,则会出现编译器错误,因此看起来关键是要在匿名类型中使用相同的名称。 Or just have the result in a defined type :) 或者只是在定义的类型中得到结果:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM