2011-03-21 29 views
4

我想通過幾個關鍵字搜索書籍的數據庫。我提供的關鍵詞越多,搜索範圍就越窄。這裏是我的代碼:Queryable.Intersect()與SQLite和Linq不給予預期的結果

var words = text.Split(' '); 

IQueryable<Reference> query = null; 

foreach (string word in words) 
{ 
    var result = from r in _dbConnection.GetTable<Reference>() 
       where r.Title.Contains(word) 
       || r.ReferenceAuthor.Any(a => a.Person.LastName.Contains(word) || a.Person.FirstName.Contains(word)) 
       || r.ReferenceCategory.Any(c => c.Category.Name.Contains(word)) 
       || r.ReferenceKeyword.Any(k => k.Keyword.Name.Contains(word)) 
       orderby r.Title 
       select r; 

    query = query == null ? result : query.Intersect(result); 
} 

query.OrderBy(r => r.Title); 

問題是,搜索實際上並沒有變窄我提供的關鍵字越多。結果甚至取決於我提供關鍵字的順序。 另外,如果涉及多個關鍵字,那麼最後的OrderBy()調用將無法可靠地工作。我的想法是否有缺陷,或者我實施它的方式?

+0

我正在使用System.Data.SQLite.SQLiteConnection和System.Data.Linq.DataContext。 – 2011-03-21 08:08:52

回答

5

你是closing over the word變量,遇到access to modified closure問題。

在循環的每次迭代中,您都將words集合中的字符串值捕獲到變量word中。但LINQ使用延遲執行,並且只有在循環完成之後,您的查詢纔會執行,此時您的查詢的所有實例都會捕獲相同的單詞變量 - 因此,您會看到您的結果因所提供的搜索關鍵字的順序而異。

要解決此問題,請在循環的每次迭代中取一個變量的本地副本。

foreach (string w in words) 
{ 
    string word = w; 
    ... 
+0

另一個解決方法是在每次迭代中調用'ToArray()'。然而,你的表現可能會受到影響 – 2011-03-21 08:45:03

+1

我不推薦這種「解決方法」,因爲您陳述的原因。它隱藏了一個問題,並且意味着代碼根本無法擴展。稍後有人可能會來,並修復性能問題,並意外重新介紹當前的錯誤。 – 2011-03-21 08:49:23

+0

啊哈,這似乎就是它。謝謝! – 2011-03-21 08:50:22