2

我正在开发一个从 LINQ 表达式(基本上是 LINQ-to-SQL 的修改子集)生成 SQL 的库。我正在使用有区别的联合来建模 SQL 表达式,但遇到了一些(感知的?)限制。我想做类似以下的事情(注意最后一行):

type SqlSourceExpression =
    | Table of string
    | Join of JoinType * SqlSourceExpression * SqlSourceExpression * SqlExpression //ie, left, right, predicate

and SqlExpression =
    | Source of SqlSourceExpression
    | OrderBy of SqlExpression * SortDirection
    | Select of SqlSourceExpression * SqlExpression * OrderBy list //can't do this

我可以执行以下操作:

type SqlOrderByExpression = SqlExpression * SortDirection

...并将最后两行更改为:

    | OrderBy of SqlOrderByExpression
    | Select of SqlSourceExpression * SqlExpression * SqlOrderByExpression list

但这似乎有两个问题:

  1. SqlOrderByExpression 不是 SqlExpression。这使得很难使用访问者模式(也许这就是问题所在?)。这意味着在遍历 Select 表达式时,我无法通过将每个表达式传递给 Visit(expr:SqlExpression) 的表达式来迭代顺序列表。

  2. SqlOrderByExpression 仅仅是一个元组的类型别名,所以没有类型信息被保留。这会损害 IMO 的可读性。

有没有更好的方法来建模这个?我尝试了继承路线,但我认为 DU 更容易使用(除非有提到的困难)。

4

2 回答 2

1

当您使用 FP 技术 (DU) 时,您不需要记住 OOP 模式,只需使用高阶函数(折叠、映射、拉链等)。

如果您只想查看匹配代码的特定视图,则可以使用活动模式:

let (|OrderByTerm|OrderByList|_|)= function
  |OrderBy x -> Some (OrderByTerm x)
  |Select (_,_,xs) -> Some (OrderByList xs)
  |_ -> None
于 2009-12-09T18:04:34.367 回答
0

我不知道为什么SqlExpression,作为一个受歧视的工会,有OrderBy和的案例Select。什么可以进入OrderBy?

我认为受歧视的工会使这变得比需要的更加困难。我认为SqlSourceExpressionSqlOrderByExpression并且SqlSelectExpression可以是不同的类型。如果您担心元组难以阅读,您可以将它们记录下来(这就是我在您的情况下会做的事情)。

我认为SqlExpression当您开始表示表达式树时,有区别的联合将很有用(1 + SUM(ISNULL(Value1, Value2))) / COUNT(*),其中语法更灵活。

于 2009-12-09T17:52:51.387 回答