代码之家  ›  专栏  ›  技术社区  ›  esac

如何将多个LINQ查询组合成一个结果集?

  •  3
  • esac  · 技术社区  · 14 年前

    我有一个多选复选框。根据选中的是哪一个,我希望将结果组合到单个查询中。有点像:

    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.
    

    你知道如何选择性地结合这些吗?

    4 回复  |  直到 14 年前
        1
  •  8
  •   Ben M    14 年前

    假设查询的类型相同,则可以在条件语句之外定义查询。

    首先,创建与参数类型相同的空可枚举的Helper方法:

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

    然后,新代码:

    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
    

    这执行得很好,因为在枚举查询之前不会实际执行查询,如对 ToList() .

        2
  •  0
  •   Frank    14 年前

    如果您不使用var,而是使用已知的类型,那么可以通过以下方式初始化query1和query2:

    Enumerable.Empty<T> 如果复选框未被选中。

        3
  •  0
  •   Antony Scott    14 年前

    我只是在一个控制台应用程序中尝试了这个,因为我很好奇,它只是工作了……

    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);
            }
        }
    }
    

    但是,如果将匿名类型中的字段名更改为不同的字段名,则会收到一个编译器错误,因此看起来关键在于匿名类型中的名称相同。或者只是将结果定义为类型:)

        4
  •  0
  •   Richard Anthony Hein    14 年前

    使用 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));
        }
    }