我在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
/ And
本身不是表达式的一部分。
无论解决方案是3行收集技巧还是全新的类系列都无关紧要。可维护性和可扩展性很重要 - 它一定不是黑客。如果有人知道解决这类问题的设计模式,我会非常有兴趣看到它。
编辑:根据要求,一些示例代码只使用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)
输出:
{{1}}
答案 0 :(得分: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”);熊请记住,“And”和“Or”不能使用,因此必须提出相同的名称)。通过遵循当前版本的Class
之类的想法,您可能会包含AddConnector
函数,但这会使一切变得太乱(每次两次调用,将表达式与连接器关联起来很困难等等) )。我建议你改变AddExpression,使它至少接受两个参数:Expression和Connector(参考先前输入的Expression或下一个);通过这种方式,您可以并行填充两个列表(ExprChain
和ExprConn
),并使它们完美协调,以便在ToString()
中使用。
答案 1 :(得分: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))