我有一个内存对象数组,表示我想通过例如:
查询的复合键public class Key
{
public string Part1 {get;set;}
public string Part2 {get;set;}
}
现在说我有一个IQueryable<Table1>
,我想用上面的Key
返回所有记录。 Table1没有代理键,它有一个由2列组成的复合键。我也想避免每行检索。
我该怎么做?我尝试了标准连接,但由于显而易见的原因,当混合中抛出内存对象时,我的ORM会感到困惑。
答案 0 :(得分:3)
在类似的情况下,我发现最好的解决方案是在数据库中完成第一次选择,然后是内存中的完全匹配:
var parts1 = Keys.Select(k => k.Part1).ToArray();
var parts2 = Keys.Select(k => k.Part2).ToArray();
var dbSelection = context.TableRecords.Where(r => parts1.Contains(r.Part1)
&& parts2.Contains(r.Part2);
var finalSelection = from record in dbSelection
.AsEnumerable() // to memory
join key in Keys on new { record.Part1, record.Part2 }
equals
new { key.Part1, key.Part2 }
select record;
如果你有钥匙
1,2
2,1
然后dbSelection
还会包含{1,1
}和{2,2}
(但绝不是绝大多数其他记录)。这些将被第二个查询过滤掉。
优点是数据库查询可以利用索引,如果使用计算键(如连接键值),这是不可能的。
缺点是您必须确保parts1
和parts2
不能过度增长,否则SQL IN
语句会因为元素太多而变得非常低效甚至崩溃(我们在这里讨论数以千计的Sql Server项目。但对于使用Contains
的任何解决方案都是如此。
答案 1 :(得分:1)
解决方法可以使用连接
这样的事情。var keys = new List<Key> {
{new Key {Part1="12", Part2="3"},
{new Key {Part1="1", Part2="23"}
};
var concatenatedKeys = keys.Select(m => m.Part1 + "~" + m.Part2).ToList();
var queryable = repository.MyEntity.Where(x => concatenatedKeys.Contains(x.CompositeKey1 + "~" + x.CompositeKey2);
分隔符(在这种情况下为~
)是任意的,意思是在字符串中找不到的字符。
这是为了避免“错误”匹配(例如12和3对比1和23)