2013-02-21 61 views
0

當人們搜索我的網站時,我不想只搜索值(q),我想用空格作爲分隔符搜索每個單詞。我編寫了大部分代碼,但有些部分我不知道該怎麼做。如何使用EntityFramework爲搜索交叉多個查詢?

你可以檢查下面的代碼中的「待辦事項」,並建議我一個辦法嗎?或者可能是一個完全不同的方法順便說一句,如果可能的話,我想保留SQL代碼的一部分,因爲它對我來說更自然,但所有的TODO都可以在LINQ中完成。

感謝

下面是代碼:

[HttpPost] 
     public ActionResult Search(string q) 
     { 
      ViewBag.q = q; 

      String[] strQueries = q.Split(' '); 

      //TODO: Create an array of type var??? 

      foreach (string str in strQueries) 
      { 
       var recipesTemp = db.Recipes.SqlQuery(
       String.Format(
       "SELECT * FROM Recipe WHERE Name LIKE '%{0}%' " + 
       "UNION ALL " + 
       "SELECT * FROM Recipe WHERE IDRecipe IN (" + 
       " SELECT IDRecipe FROM Subtitle WHERE Name LIKE '%{0}%') " + 
       "UNION ALL " + 
       "SELECT * FROM Recipe WHERE IDRecipe IN (" + 
       " SELECT IDRecipe FROM RecipeTag " + 
       "  INNER JOIN Tag ON Tag.IDTag = RecipeTag.IDTag " + 
       " WHERE Name LIKE '%{0}%') " + 
       "UNION ALL " + 
       "SELECT * FROM Recipe WHERE IDRecipe IN (" + 
       " SELECT IDRecipe FROM Subtitle " + 
       "  INNER JOIN Ingredient ON Ingredient.IDSubtitle = Subtitle.IDSubtitle " + 
       " WHERE QuantityAndName LIKE '%{0}%')", str)).Distinct().OrderBy(r => r.Name).ToList(); 

       //TODO: Add recipesTemp to the array of var 
      } 

      var recipes = //TODO: INTERSECT the results from all the recipesTemp in the array of type var 

      return View("Search", recipes); 
     } 
+0

如果有一個「祕方」在這裏,它是一個SQL注入攻擊。 – 2013-02-21 02:46:21

+0

除了安全問題之外,你有關於如何做到這一點的想法嗎?在這種情況下,你會建議如何避免SQL注入攻擊? – 2013-02-21 03:13:27

回答

1

下面的代碼將這樣的伎倆:

 var selectedRecipies = new List<IEnumerable<Recipy>>(); 

     foreach(...) 
     { 
      ... 
      selectedRecipies.Add(recipesTemp); 
     } 

     var recipies = selectedRecipies.Aggregate((a, i) => a.Intersect(i)); 

此外,在你的地方,我會還採取@KirkWoll的評論成帳戶並使用FullTextSearch而不是LIKE。

+0

我知道什麼是FullTextSearch(例如Lucene),但我總是認爲這是搜索大量的文本。在我的情況下,我只在4個非常小的表格(長度爲50的varchar)中搜索。 FullTextSearch是否適合這個? – 2013-02-21 11:43:47

+0

對,MSSQL中有一個'內置的'FullTextSearch功能,所以你不必安裝Lucene。不過,它會顯示大量文字或synonims的搜索結果,因此您可能會忘記它,但實際上它會成爲您的問題。 – Dima 2013-02-21 14:56:20

+0

對於您的信息,我使用您的技術,並將我的查詢中的SQL部分轉換爲linq以避免sql注入!非常感謝:) – 2013-02-21 23:40:50

0

對於strQueriesstr你創建按名稱排序,並存儲在List<T>明顯格式化的SQL查詢,其中TRecipe(?)。嘗試類似的東西:

var allRecipes = strQueries.Select(str => db.Recipes.SqlQuery(
    String.Format(
     "SELECT * FROM Recipe WHERE Name LIKE '%{0}%' " + 
     "UNION ALL " + 
     "SELECT * FROM Recipe WHERE IDRecipe IN (" + 
     " SELECT IDRecipe FROM Subtitle WHERE Name LIKE '%{0}%') " + 
     "UNION ALL " + 
     "SELECT * FROM Recipe WHERE IDRecipe IN (" + 
     " SELECT IDRecipe FROM RecipeTag " + 
     "  INNER JOIN Tag ON Tag.IDTag = RecipeTag.IDTag " + 
     " WHERE Name LIKE '%{0}%') " + 
     "UNION ALL " + 
     "SELECT * FROM Recipe WHERE IDRecipe IN (" + 
     " SELECT IDRecipe FROM Subtitle " + 
     "  INNER JOIN Ingredient ON Ingredient.IDSubtitle = Subtitle.IDSubtitle " + 
     " WHERE QuantityAndName LIKE '%{0}%')", str)).Distinct().OrderBy(recipe => recipe.Name)) 
    .SelectMany(recipe => recipe); 

allRecipes應該通過後類型IEnumerable<Recipe>的。

0

試試這個辦法,這將導致一個SQL語句:

var names = q.Split(' '); 

if(names.Any()) 
{ 
    var firstName = names[0]; 

    var query = context.Recipes.Where (q => q.Name.Contains(firstName)); 
    // other unions ... 
    // query = query.Union(context.Recipes.Where (... 
    foreach (var name in names.Skip(1)) 
    { 
     query = query.Union(context.Recipes.Where (q => q.Name.Contains(name))); 
     // other unions ... 
     // query = query.Union(context.Recipes.Where (... 
    } 

    // query evaluated now 
    var recipes = query.ToList(); 
} 
+0

我不確定,但我認爲使用你的方法,第一個名字將只搜索配方名稱,但另一個將搜索所有其他地方(標籤,配料等)。我希望分裂的所有名字都在4個地方進行搜索。但我理解你的答案背後的想法,並會嘗試今晚實施它 – 2013-02-21 11:41:37

+0

我明白你的意思了,更新了答案。 – Phil 2013-02-21 12:13:12