2014-10-01 56 views
1

我有這種方法,應該採取未知量的ID。 我得到了這種方法幾乎完成,但它不安全,但出於顯而易見的原因,我知道我可以寫我自己的方法去除參數,但我會更舒適通過使用一些內置的方法。如何使用實體框架SqlQuery來保護SQL參數?

這裏是方法

public static List<LocationModel> FetchCitiesByAreas(IEnumerable<string> areas) 
    { 
     using (var db = new BoligEnt()) 
     { 
      var sqlQuery = new StringBuilder(); 
      var first = true; 

      sqlQuery.Append("SELECT DISTINCT a.city AS City, a.zip AS Zip "); 
      sqlQuery.Append("FROM zip_city AS a "); 
      sqlQuery.Append("WHERE country = 1 "); 

      foreach (var d in areas) 
      { 
       if (first) 
       { 
        sqlQuery.Append("AND a.area_id = '" + d + "'"); 
        first = false; 
       } 
       else 
       { 
        sqlQuery.Append("OR a.area_id = '" + d + "'"); 
       } 

      } 

      return db.Database.SqlQuery<LocationModel>(sqlQuery.ToString()).ToList(); 
     } 
    } 

我知道它已經建立了,但正如我前面提到的我不知道ID的確切量會在

db.Database.SqlQuery<LocationModel>("SELECT * FROM table WHERE id = @p0 ;", id).ToList(); 

感謝

此功能
+0

您使用的是什麼DBMS? Sql Server? – paqogomez 2014-10-01 20:36:29

+0

實體框架6與MySql服務器 – 2014-10-01 20:38:40

+1

我認爲你有點錯過了EF的點 - 這是:避免必須編寫所有的SQL,而是使用漂亮的Linq查詢來獲取您需要的數據..... – 2014-10-01 20:43:01

回答

3

雖然我完全同意paqogomez,因爲你應該只使用LINQ做查詢時,.SqlQuery必須採取一個參數數組的能力。你可以改變你的陳述如下所示:

var sqlQuery = new StringBuilder(); 

sqlQuery.Append("SELECT DISTINCT a.city AS City, a.zip AS Zip "); 
sqlQuery.Append("FROM zip_city AS a "); 
sqlQuery.Append("WHERE country = 1 "); 

for (int i = 0; i < areas.Count; i++) 
{ 
    if (i == 0) 
    { 
     sqlQuery.Append("AND (a.area_id = @p" + i.ToString()); 
    } 
    else 
    { 
     sqlQuery.Append(" OR a.area_id = @p" + i.ToString()); 
    } 
} 
sqlQuery.Append(")"); 

var results = db.Database.SqlQuery<LocationModel>(sqlQuery.ToString(), areas.ToArray()).ToList(); 

我在查詢中添加了缺少的括號,以正確地過濾掉OR結果。我也假設areas就像是一個List,或者至少可以輕鬆從中獲得數量。

+0

優秀的答案,我喜歡你的循環想法。+1 – paqogomez 2014-10-01 21:12:28

+0

感謝的人是地區只是一個列表所以它可以計算,它非常好,非常感謝你。 – 2014-10-01 21:16:17

3

爲什麼不使用Linq?

var locations = (from zip in db.zip_city 
       where areas.Contains(zip.area_id) && zip.Country == 1 
       select new LocationModel{ 
        City = zip.City, 
        Zip = zip.Zip 
        }) 
      .Distinct() 
      .ToList(); 

如果你仍然想參數化查詢,則需要使用EntityCommand

還要注意的是,因爲你還沒有把括號圍繞你OR報表查詢將會失敗。

我建議構建你這樣的SQL:

string sqlQuery = 
    @"SELECT DISTINCT a.city AS City, a.zip AS Zip 
     FROM zip_city AS a 
     WHERE country = 1 AND (1=0 " 

    for (int i = 0; i < areas.Count; i++) 
    { 
     sqlQuery.Append("OR a.area_id = @d" + i.ToString() + " "); 
    } 
    sqlQuery.Append(")"); 
+0

是的我知道我可以使用linq這個方法我張貼的是一個精確的方法的簡化版本。原始方法有一些連接和東西,實體框架並沒有像我想要的那樣處理它,我在原始sql中獲得了很好的性能提升 – 2014-10-01 20:54:47

+0

避免使用'for'循環的巧妙技巧'如果'聲明 - 但不應該是'1 = 0'? '1 = 1'將評估爲真,並完全忽略所有其他的'OR'語句...... – entropic 2014-10-01 21:16:21

+0

@entropic你是正確的,'OR'需要假開始,我主要用'AND' – paqogomez 2014-10-01 21:22:29