这个问题让我困惑了一段时间,让我分解一下。
我需要使用Where
,Select
语句和事物的相同逻辑来查询两个不同的集合,并且我事先并不知道这个逻辑。说我有两个集合:
var arrayOne = {"Germane", "Henry", "Charissa", "Evan", "Zorita"};
var arrayTwo = {"Athena", "Darryl", "Zelenia", "Honorato", "Macon"};
还有一些过滤逻辑:
var result = arrayOne.Where(x => x.Length > 3).Select(x => x.Length);
如何在不复制代码本身的情况下将此逻辑复制到第二个数组?有一种方法可以通过代表(这是我现在的代表)来做到这一点
Func<IEnumerable<string>, IEnumerable<int>> query = x => x.Where(x => x.Length > 3).Select(x => x.Length);
var result1 = query(arrayOne);
var result2 = query(arrayTwo );
但是我需要逐步构建查询,而不是内联,比如
var query = SomeQueryGenerator.CreateQuery();
query.Where(x => x.Length > 3)
if(someCondition)
{
// Totally random query
query.Where(x => x.Length % 2 == 0);
}
var result = query(arrayOne);
这就是问题所在。现在让我展示一下到目前为止我所做的事情(并且更多地打破我的情况)
当我们尝试将大量数据导入数据库时出现了问题。这个数据有大约20k行,它可以包含一些重复项(我们不想存储),因此检查我们是否已经有特定行(它通过一些合法ID检查)非常重要。我们将NHibernate用作ORM,默认情况下,它会经常在每个INSERT
语句之前或在任何其他时间刷新UPDATE
和SELECT
。
问题是这些刷新需要很长时间,所以将所有20k行加载到DB中需要长达10个小时。最明显的方法是将当前Session.FlushMode
设置为FlushMode.Never
并在导入结束时将其刷新。这样20k行导入大约10分钟。但问题是,当我们查询时,我们没有看到我们的重复项,因为它们还没有在数据库中,而.Where(x => x.LegalId == someId)
这样的查询即使在 实际上是已保存的行。我决定利用我们的Session
第一级缓存执行此任务,因为我们保存的所有实体都先写入其缓存中,然后在Flush
发生时写入数据库(可能不是实际写到DB直到我们的transaction.Commit
,但它会通过查询正确地找到这些entites)。
我已经设置了一个帮助程序类,可以查询缓存和原始数据库,并且它可以正确地在缓存中找到尚未包含在DB中的entite(上面的内联委托示例)
但我需要能够逐步查询事情,而且我现在完全迷失了。
我们无法从Expression
获得IQueryable
并将其粘贴到另一个IQueryable
。我们无法创建一些虚拟IEnumerable
或.Where
对象并传递它,抛出.Select
或{{1}},因为我们将绑定到特定的来源,并且我们也无法交换这些来源(至少我没有办法做到这一点)。
我需要一些关于这个问题的新想法,先谢谢。
- 更新数据重复
我们无法预处理数据,让我解释原因。
我们说我们的文件中有建筑物。某些构建可以属于组织。如果我们遇到具有指定组织的建筑物,我们需要创建它并存储在DB中。这样,我们不仅有建筑物(它们本身不重复),也有它们的组织。几个建筑物完全有可能拥有相同的组织,但我们不需要多次创建这些组织。当然我们可以先解析这个文件,获取所有组织,先导入它们然后再导入构造,但这太复杂了,而且,正如我在评论中所说,问题更为通用,它&# 39;超出了这个导入逻辑的范围
答案 0 :(得分:0)
仍然不太确定你正在尝试做什么,但我想这可以帮助你朝着正确的方向:
var arrayOne = new []{"Germane", "Henry", "Charissa", "Evan", "Zorita"};
var arrayTwo = new []{"Athena", "Darryl", "Zelenia", "Honorato", "Macon"};
//var result1 = arrayOne.Where(x => x.Length > 3).Select(x => x.Length);
bool condition1 = true;
bool condition2 = false;
bool condition3 = true;
var fnc = (Func<IEnumerable, IEnumerable>)(source =>
{
var qry = source;
if (condition1)
{
qry = qry.Cast<string>().Where(x => x.Length > 3);
}
if (condition2)
{
qry = qry.Cast<int>().Where(x => x < 10);
}
if (condition3)
{
return qry.Cast<string>().Select(x => x.Length);
}
return qry;
});
var result_v2_1 = fnc(arrayOne);
var result_v2_2 = fnc(arrayTwo);
请注意,将consition1和condition2设置为true会导致错误。还要注意,condition2与String []的输入结合也会导致错误。
答案 1 :(得分:0)
虽然LINQ查询绑定到序列,但可以更改该序列并重新评估查询。所以你可以做这件事:
var arrayOne = new[] {"Germane", "Henry", "Charissa", "Evan", "Zorita"};
var arrayTwo = new[] {"Athena", "Darryl", "Zelenia", "Honorato", "Macon"};
// bind to an empty sequence to start with
var source = new List<string>();
var query = source.Where (x => x.Length > 3);
if (true)
{
query = query.Where (x => x.Length % 2 == 0);
}
// change the sequence once
source.AddRange(arrayOne);
var resultOne = query.ToArray();
Console.WriteLine(string.Join(", ", resultOne));
// change the sequence again
source.Clear();
source.AddRange(arrayTwo);
var resultTwo = query.ToList();
Console.WriteLine(string.Join(", ", resultTwo));
第一个Console.WriteLine
输出:
Charissa,Evan,Zorita
第二个输出:
Athena,Darryl,Honorato
一个更简单的解决方案是为任何这些序列操作创建方法,而不是尝试全部内联:
private static IEnumerable<string> Filter(IEnumerable<string> sequence)
{
var bigOnes = sequence.Where (s => s.Length > 3);
if (true)
{
bigOnes = bigOnes.Where (s => s.Length % 2 == 0);
}
return bigOnes;
}
...
var resultThree = Filter(arrayOne);
Console.WriteLine(string.Join(", ", resultThree));
var resultFour = Filter(arrayTwo);
Console.WriteLine (string.Join(", ", resultFour));