2013-08-23 64 views
0

我在VB.NET中創建一個用於生成SQL字符串的庫。然而,生成WHERE子句(以及類似的結構)給了我一個問題。我已經確定了最簡單的where子句結構基本上是由可變分隔符分隔的一系列對象的類設計/模式

expression1 [AND expression2 [AND expressionN]] 

這是很容易的代碼來表示與Expression對象的列表 - 程序然後就必須通過每個循環中,調用其重寫ToString()方法和追加AND每次(除了最後一個)。簡單。併發症來當OR考慮:一個where子句的結構變得

expression1 [[AND|OR] expression2 [[AND|OR] expressionN]] 

我現在需要能夠既容納所有的表情,也是防不勝防是否每次從旁邊通過AND或分離OR - 本質的(expr1, andOr1, expr2, andOr2, ... exprN, andOrN)

的集合,我還認爲,結構可以嵌套過多,如:

(expression1 [[AND|OR] expression2]) [AND|OR] (expression3 [[AND|OR] expression4]) 

其中每個廿四括號內的一半本身就是一種表達方式。因此,我認爲該解決方案涉及通過擴展Expression類進一步,使得表達可以是表達式的鏈:我有一個新的類ExpressionFromChainOfExpressions

Public Class ExpressionFromChainOfExpressions 
    Inherits Expression 

    Private ExprChain As List(Of Expression) 

    Public Sub AddExpression(Expr As Expression) 
     If ExprChain Is Nothing Then ExprChain = New List(Of Expression) 
     ExprChain.Add(Expression) 
    End Sub 

    Public Overrides Function ToString() As String 
     Dim outStr As String = "(" 
     For i = 0 To ExprChain.Count - 1 
      outStr &= Expr.ToString() 
      If i < ExprChain.Count - 1 
       'ToDo: Determine [AND|OR] and append 
       'OLD: outStr &= " AND " 
      End If 
     Next 
     Return outStr & ")" 
    End Function 
End Class 

捆綁的And/Or作爲布爾標誌或一些這樣的進入Expression類感覺錯 - 了Expression應該是可重複使用的其他地方(他們也是在其他情況下,如case when expression [[and|or] expression] ...突然出現,並And/Or本身不是表達式的一部分

不要緊,能否解決。是3線收藏伎倆或一個全新的家庭。可維護性和可擴展性非常重要 - 它不能被破解。如果有人知道解決這類問題的設計模式,我很樂意看到它。


編輯:按照要求,只是使用And(從實際的代碼大大簡化由於真實運動部件的數量)的一些示例代碼:

Public MustInherit Class Expression 
    Public MustOverride Function ToString() As String 
End Class 


Public Class ExpressionFromString 
    Inherits Expression 

    Private ExprString As String 

    Public Sub New(ExprString As String) 
     Me.ExprString = ExprString 
    End Sub 

    Public Overrides Function ToString() As String 
     Return ExprString 
    End Function 
End Class 


Public Class ExpressionFromChainOfExpressions 
    Inherits Expression 

    Private ExprChain As List(Of Expression) 

    Public Sub AddExpression(Expr As Expression) 
     If ExprChain Is Nothing Then ExprChain = New List(Of Expression) 
     ExprChain.Add(Expression) 
    End Sub 

    Public Overrides Function ToString() As String 
     Dim outStr As String = "(" 
     For i = 0 To ExprChain.Count - 1 
      outStr &= Expr.ToString() 
      If i < ExprChain.Count - 1 
       outStr &= " AND " 
      End If 
     Next 
     Return outStr & ")" 
    End Function 
End Class 

主要方法:

Public Module Module1 
    Dim myExpr1 = New ExpressionFromString("A = B") 
    Dim myExpr2 = New ExpressionFromString("C > 100") 
    dIM myExpr3 = New ExpressionFromString("D Is Null") 

    Dim myNestedChain = New ExpressionFromChainOfExpressions() 
    myExprChain.Add(myExpr1) 
    myExprChain.Add(myExpr2) 
    Console.WriteLine("WHERE " & myNestedChain.ToString()) 

    Dim myOuterChain = New ExpressionFromChainOfExpressions() 
    myOuterChain.Add(myNestedChain) 
    myOuterChain.Add(myExpr3) 

    Console.WriteLine("WHERE " & myOuterChain.ToString()) 
End Module 

輸出:

WHERE (A = B AND C > 100) 
WHERE ((A = B AND C > 100) AND D Is Null) 
+0

我不完全確定你想要完成什麼;但是您知道And/Or(和AndAlso等替代方法)是ExpressionType枚舉的一部分(http://msdn.microsoft.com/zh-cn/library/bb361179.aspx),不是嗎? – varocarbas

+0

是的,謝謝,我知道。爲了澄清,'And' /'Or'這裏只是一個輸出字符串,它需要存儲在某個地方並用於鏈表達式(程序不會使用它們來運行條件檢查本身)。對於所有的程序而言,它可能是'Bananas' /'Waffles' - 問題是我需要一些方法來定義一個鏈,鏈中的每個鏈接都由'And'或'Or'(或'Bananas'或Waffles'):) – Kai

+0

你能寫一個實際的例子給你的類的輸入(ExpressionFromChainOfExpressions變量是...)和ToString重載函數的預期輸出(當執行.ToString()時我想得到...)?這肯定有助於澄清你想要的東西。 – varocarbas

回答

1

這裏談到的是如何面對你的問題的建議:

Public Class ExpressionFromChainOfExpressions 
    Inherits Expression 

    Private ExprChain As List(Of Expression) 
    Private ExprConn As List(Of Connector) 
    Public Enum Connector 
     AndConn 
     OrConn 
    End Enum 
    Public Sub AddExpression(Expr As Expression) 'Might have to be changed to account for connectors 
     If ExprChain Is Nothing Then ExprChain = New List(Of Expression) 
     ExprChain.Add(Expr) 
    End Sub 
    Public Overrides Function ToString() As String 
     Dim outStr As String = "(" 
     For i = 0 To ExprChain.Count - 1 
      outStr &= ExprChain(i).ToString() 
      If i < ExprChain.Count - 1 Then 
       outStr &= 'will account for the given connector (as stored in ExprConn) 
      End If 
     Next 
     Return outStr & ")" 
    End Function 
End Class 

等價爲您定義輸入Expressions,定義輸入Connectors(一Public Enum包括所有你想要的替代品(「與」和「或」爲暫且);請記住「And」和「Or」不能使用,因此必須提供相同的名稱)。通過遵循當前版本Class的想法,您可能會包含一個AddConnector函數,儘管這會使一切都太亂(每次兩個調用,難以將表達式與連接器關聯等)。我推薦你改變AddExpression,使它至少接受兩個參數:表達式和連接器(引用先前輸入的表達式或下一個表達式);通過這種方式,您將能夠並行填充兩個列表(ExprChainExprConn),並使它們完美協調以便在ToString()中使用。

+0

我回過頭來發表自己在咖啡休息腦波中發現的答案(我發現咖啡休息時間有時候是我一天中最有生產力的部分!)......並且它幾乎與這個解決方案一字不符。 Mine使用了一個字符串而不是Enum,所以我確實可以使用'a = b WAFFLES c> 100',儘管我仍在辯論使用哪一個。 Mine還有一個'IsNested'布爾成員,它決定它是否圍繞輸出包裹'()',這可以更好地控制更復雜的嵌套。無論如何,完美的答案,謝謝! – Kai

+0

@kai歡迎您。我建議你依靠一個枚舉。它比看起來好得多;主要是當你不得不使用給定的類時。 – varocarbas

0

我自己對varocarbas的解決方案的變化,允許更好地控制嵌套通過IsNested布爾值,並且不依賴於兩個集合的排序:

Public Class ExpressionFromChainOfExpressions 
    Inherits Expression 

    Private ExprChain As List(Of Expression) 

    'Alternatively use an Enum as per varocarbas's solution 
    'for better consistency control 
    Private ChainWord As String 

    'If true, wraps () around ToString()'s output 
    Private IsNested As Boolean 

    Public Sub New(ByVal ChainWord As String, ByVal IsNested As Boolean) 
     Me.ChainWord = ChainWord 
     Me.IsNested = IsNested 
    End Sub 

    Public Sub AddExpression(ByVal Expr As Expression) 
     If ExprChain Is Nothing Then ExprChain = New List(Of Expression) 
     ExprChain.Add(Expr) 
    End Sub 

    Public Overrides Function ToString() As String 
     Dim outStr As String = "" 
     If IsNested Then outStr = "(" 

     For i = 0 To ExprChain.Count - 1 
      outStr &= ExprChain(i).ToString() 
      If i < ExprChain.Count - 1 Then 
       outStr &= String.Format(" {0} ", ChainWord) 
      End If 
     Next 

     If IsNested Then outStr = ")" 

     Return outStr 
    End Function 
End Class 

允許複雜的輸出如

expr1 AND expr2 OR (exp3 AND (expr4 OR expr5 AND expr6 AND expr7))