2011-03-16 73 views
0

嘿, 我想編寫一個查詢的「凡」在查詢是一個字符串像「動態查詢LINQ到xml的VB.NET

昏暗查詢的String =」 NAME = XXXX和日期> 10 「

昏暗的T =從書doc.Descendants(」 書「)選擇_ [名] = book..value,[日期] = book..value .... 凡(查詢)

我在運行時構建查詢字符串

謝謝..

+0

爲什麼不在你那裏做什麼工作?它是拋出一個異常,沒有得到你期望的結果或什麼? – Manatherin 2011-03-16 09:46:02

+0

它引發異常,Where()可以得到布爾值 – Beno 2011-03-16 11:52:46

回答

0

我並不是說這是你的情況,但我從ASP經典的人那裏看到了很多,我們經常用它來構建動態SQL字符串。我們傾向於希望LINQ在部分代碼中給我們更多的權力,但讓我們在其他地方使用字符串。不幸的是,這不是事實。 Where需要一個布爾參數,並且沒有辦法。你可以編寫自己的使用反射的解析器,並最終返回一個布爾值,但是你會寫很多可能容易出錯的代碼。下面是你真的應該這樣做:

假設這是我們的數據類:

Public Class TestObject 
    Public Property Name As String 
    Public Property Job As String 
End Class 

下面是我們的測試數據:

Dim Objects As New List(Of TestObject) 
    Objects.Add(New TestObject() With {.Name = "A", .Job = "Baker"}) 
    Objects.Add(New TestObject() With {.Name = "B", .Job = "President"}) 
    Objects.Add(New TestObject() With {.Name = "C", .Job = "Bus Driver"}) 
    Objects.Add(New TestObject() With {.Name = "D", .Job = "Trainer"}) 

你想要做什麼是創建一個代表一個變量要搜索的數據:

''//This variable simulates our choice. Normally we would be parsing the querystring, form data, XML values, etc 
    Dim RandNum = New Random().Next(0, 3) 
    Dim LookForName As String = Nothing 
    Select Case RandNum 
     Case 0 : LookForName = "A" 
     Case 1 : LookForName = "B" 
     Case 2 : LookForName = "C" 
    End Select 

    ''//Query based on our name 
    Dim Subset = (From O In Objects Select O Where (O.Name = LookForName)).ToList() 

如果有時您需要在Job上進行搜索,有時甚至是metimes你沒有你就可能需要編寫幾個查詢:

Dim Subset As List(Of TestObject) 
    Select Case RandNum 
     Case 0 
      Subset = (From O In Objects Select O Where (O.Name = "A" And O.Job = "Baker")).ToList() 
     Case Else 
      Select Case RandNum 
       Case 1 : LookForName = "B" 
       Case 2 : LookForName = "C" 
      End Select 
      Subset = (From O In Objects Select O Where (O.Name = LookForName)).ToList() 
    End Select 

而只是爲了解釋編寫自己的查詢分析器(這是我建議你切勿往下走的路徑),在這裏是一個非常非常非常粗糙的開始。它僅支持=並且僅支持字符串,並且可以在多個點中斷。

Public Shared Function QueryParser(ByVal obj As Object, ByVal ParamArray queries() As String) As Boolean 
    ''//Sanity check 
    If obj Is Nothing Then Throw New ArgumentNullException("obj") 
    If (queries Is Nothing) OrElse (queries.Count = 0) Then Throw New ArgumentNullException("queries") 

    ''//Array of property/value 
    Dim NameValue() As String 
    ''//Loop through each query 
    For Each Q In queries 
     ''//Remove whitespace around equals sign 
     Q = System.Text.RegularExpressions.Regex.Replace(Q, "\s+=\s+", "=") 
     ''//Break the query into two parts. 
     ''//NOTE: this only supports the equal sign right now 
     NameValue = Q.Split("="c) 
     ''//NOTE: if either part of the query also contains an equal sign then this exception will be thrown 
     If NameValue.Length <> 2 Then Throw New ArgumentException("Queries must be in the format X=Y") 

     ''//Grab the property by name 
     Dim P = obj.GetType().GetProperty(NameValue(0)) 
     ''//Make sure it exists 
     If P Is Nothing Then Throw New ApplicationException(String.Format("Cannot find property {0}", NameValue(0))) 
     ''//We only support strings right now 
     If Not P.PropertyType Is GetType(String) Then Throw New ApplicationException("Only string property types are support") 

     ''//Get the value of the property for the supplied object 
     Dim V = P.GetValue(obj, Nothing) 
     ''//Assumming null never equals null return false for a null value 
     If V Is Nothing Then Return False 
     ''//Compare the two strings, return false if something doesn't match. 
     ''//You could use String.Compare here, too, but this will use the current Option Compare rules 
     If V.ToString() <> NameValue(1) Then Return False 
    Next 

    ''//The above didn't fail so return true 
    Return True 
End Function 

此代碼將允許你寫:

Dim Subset = (From O In Objects Select O Where (QueryParser(O, "Name = A", "Job = Baker"))).ToList() 
0

沒有,沒有什麼直接像你要找的內容,您可以在傳遞一個字符串。正如他們所說的,當你擁有的只是一把錘子時,一切都看起來像一個釘子......真正的問題是你需要學習LINQ擅長的東西並將它應用於你的代碼(如果它很合適),而不是比嘗試使用動態構建的SQL查詢字符串做得更好。

你應該做的是讓那些「Where」子句強制類型化。你目前的代碼有很大的潛力可以炸燬並且很難調試。

你可以做什麼,而不是是這樣的(對不起,使用C#,已經有一段時間,因爲我已經感動VB.NET):

var query = from book in doc.Descendants("books") 
      select book; 

if(needsNameComparison) 
{ 
    query = query.where(book.Name == nameToCompare); 
} 

if(needsDateComparison) 
{ 
    query = query.Where(book.Date > 10); 
} 

List<book> bookList = query.ToList(); 

使用LINQ,「查詢」是不是真正運行直到「ToList()」調用。由於它使用後期執行,所以查詢是動態的,因爲它正在建立,直到它實際需要運行。這與您在提前構建查詢字符串之前希望使用的代碼類似,然後在特定點執行它。