1

我有一个内存对象数组,它们代表我想要查询的复合键,例如:

public class Key
{
    public string Part1 {get;set;}
    public string Part2 {get;set;}
}

现在说我有一个IQueryable<Table1>,我想用上面Key的 s 返回所有记录。Table1 没有代理键,它有一个由 2 列组成的复合键。我也想避免每行检索。

我怎样才能做到这一点?我尝试了标准连接,但由于明显的原因,当内存中的对象被混合时,我的 ORM 会感到困惑。

4

2 回答 2

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

thendbSelection还将包含{1,1} 和{2,2}(但不是绝大多数其他记录)。这些被第二个查询过滤掉了。

优点是数据库查询可以利用索引,如果您使用计算键(如连接键值),这是不可能的。

缺点是你必须确保parts1并且parts2不能过度增长,否则SQLIN语句会因为元素太多而变得非常低效甚至崩溃(我们在这里为Sql Server谈论数千个项目)。但对于任何使用Contains.

于 2014-01-10T20:33:32.517 回答
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)

于 2014-01-10T07:27:57.263 回答