2014-01-10 47 views
1

我的代表,我想通過例如查詢組合鍵存儲對象的數組:如何使用ORM + LINQ通過組合鍵進行查詢?

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

現在都說我是個IQueryable<Table1>,我想上述Key迴歸的所有記錄。 Table1沒有代理鍵,它有一個由2列組成的組合鍵。我也想避免每行檢索。

我該怎麼做?我嘗試了標準連接,但由於顯而易見的原因,當內存對象被混入時,我的ORM會感到困惑。

回答

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,例如)

+0

這可能會有巨大的缺點,因爲查詢不會在服務器端進行評估。 – Alwyn

+0

@Alwyn沒有。這是該解決方案的「優點」。 –

+0

聽起來不錯,但是這可以索引? – Alwyn

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}(但絕大多數其他記錄)。這些被第二個查詢過濾掉。

優點是數據庫查詢可以利用索引,如果您使用計算鍵(如連接的鍵值),這是不可能的。

的缺點是,你必須確保parts1parts2不能生長過度,否則SQL語句IN將變得非常低效甚至因爲太多的元素的崩潰(我們談論項目的成千上萬在這裏爲SQL服務器)。但對於使用Contains的任何解決方案,情況都是如此。

+0

好的嘗試我想答案是真的,它不能做到。雖然預過濾有所幫助,但正如您所說的,它對於較大的問題無法擴展。 – Alwyn

+0

不,這種'Contains'或'IN'語句的可伸縮性缺乏真正的PIA。我也有解決方案,我在'UNION'查詢中,'IN'是分塊完成的。精心+醜陋。 –