Linq 基于属性参数化F#查询

Linq 基于属性参数化F#查询,linq,f#,type-providers,quotations,Linq,F#,Type Providers,Quotations,我想找出几个表上的一些常见查询。在一个非常简单的示例中,所有表都有一个DataDate列,因此我有如下查询: let dtexp1 = query { for x in table1 do maxBy x.Datadate } let dtexp2 = query { for x in table2 do maxBy x.Datadate } 基于a,我可以执行以下操作: let mkQuery t q = query { for rows in t do maxBy ((

我想找出几个表上的一些常见查询。在一个非常简单的示例中,所有表都有一个
DataDate
列,因此我有如下查询:

let dtexp1 = query { for x in table1 do maxBy x.Datadate }
let dtexp2 = query { for x in table2 do maxBy x.Datadate }
基于a,我可以执行以下操作:

let mkQuery t q  = 
        query { for rows in t do maxBy ((%q) rows) }

let getMaxDt1 = mkQuery table1 (<@ fun q -> q.Datadate @>)   
let getMaxDt2 = mkQuery table2 (<@ fun q -> q.Datadate @>)

除非我能抽象出由生成的表1、表2等的类型。

答案在很大程度上取决于您需要构造什么样的查询以及它们是静态的还是动态的。一般来说:

  • 如果LINQ主要是静态的,并且您可以轻松列出所有查询所需的所有模板,那么LINQ是非常棒的—主要的优点是它静态地检查查询类型

  • 当您的查询结构非常动态时,LINQ就不太好了,因为这样您就需要编写大量的引用,并且类型检查有时会妨碍您

如果您的查询非常动态(包括动态选择源代码),但不太复杂(例如,没有花哨的分组,也没有花哨的连接),那么编写代码从F#domain模型生成SQL查询可能会更容易

对于您的简单示例,查询实际上只是一个表名和聚合:

type Column = string
type Table = string

type QueryAggregate =
  | MaxBy of Column

type Query = 
  { Table : Table
    Aggregate : QueryAggregate }
然后,您可以使用以下方法创建两个查询:

let q1 = { Table = "table1"; Aggregate = MaxBy "Datadate" }
let q2 = { Table = "table2"; Aggregate = MaxBy "Datadate" }
将这些查询转换为SQL非常简单:

let translateAgg = function
  | MaxBy col -> sprintf "MAX(%s)" col

let translateQuery q =
  sprintf "SELECT %s FROM %s" (translateAgg q.Aggregate) q.Table

根据查询的丰富程度,转换可能会变得非常复杂,但是如果结构相当简单,那么这可能比使用LINQ构造查询更容易。正如我所说,如果不知道确切的用例,很难说什么会更好

thx。这是一个有趣的方法。我会仔细考虑的。是的,查询是动态的,我可以用报价来处理。但我很好奇,是否有什么方法可以让它更习惯/更简单,使用泛型或接口,或者(gasp)SRTP作为最后的手段。如果你走上“字符串-concat”的道路:确保你的应用程序不会进入SQL注入的危险区域。@CaringDev很好。使用
SqlCommand
运行结果查询时,最好的选择是通过
SqlParameter
添加参数(请参阅)。这样,用户输入将永远不会与查询字符串连接,您应该不会有问题!
let translateAgg = function
  | MaxBy col -> sprintf "MAX(%s)" col

let translateQuery q =
  sprintf "SELECT %s FROM %s" (translateAgg q.Aggregate) q.Table