Как объединить несколько запросов linq в один набор результатов?
У меня есть флажок множественного выбора. В зависимости от того, какой из них выбран, я хочу объединить результаты в один запрос. Вроде как:
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 ответа
Предполагая, что запросы имеют одинаковый тип, вы можете определить запросы вне условных операторов.
Во-первых, вспомогательный метод, который создает пустой перечисляемый тип того же типа, что и параметр:
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()
,
Используя 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));
}
}
Если бы вы использовали не var, а известный тип, вы могли бы инициализировать query1 и query2 через
Enumerable.Empty<T>
в случае если флажок не установлен.
Я только что попробовал это в консольном приложении, поскольку мне было любопытно, и это только работало....
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);
}
}
}
Однако, если я изменяю имена полей в анонимных типах на другие, я получаю ошибку компилятора, поэтому похоже, что ключ к тому, чтобы имена были одинаковыми в ваших анонимных типах. Или просто иметь результат в определенном типе:)