【问题标题】:Populate list with Types使用类型填充列表
【发布时间】:2017-03-27 12:00:58
【问题描述】:

我试图用我自己的类型填充列表。

let getUsers =
    use connection = openConnection()
    let getString = "select * from Accounts"
    use sqlCommand = new SqlCommand(getString, connection)
    try
        let usersList = [||]
        use reader = sqlCommand.ExecuteReader()
        while reader.Read() do
            let floresID = reader.GetString 0
            let exName = reader.GetString 1
            let exPass = reader.GetString 2
            let user = [floresID=floresID; exName=exName; exPass=exPass]
            // what here?
            ()
    with
        | :? SqlException as e -> printfn "Došlo k chybě úrovni připojení:\n %s" e.Message
        | _ -> printfn "Neznámá výjimka."

在 C# 中,我只需将新对象添加到 userList。如何将新的user 添加到列表中?还是从数据库中获取某种包含数据的列表的更好方法?

【问题讨论】:

  • 如果您已经可以从数据库中获取您需要的列表,那可能是最好的方法。除此之外,您可以使用ResizeArray<_>,即.NET 的System.Collections.Generic.List<_>usersList 当前是一个数组,在 .NET 中永远无法添加数组。
  • 您访问的是什么数据库,是否有使用 ADO 的特定原因?您应该尝试使用类型提供程序访问它。无论哪种方式,尝试取回记录的序列(IEnumerable)而不是数组。

标签: f# fsharp.data.sqlclient


【解决方案1】:

最简单的方法是使用类型提供程序,这样您就可以抽象出数据库。您可以将SqlDataConnection 用于 SQLServer,SqlProvider 用于所有内容(包括 SQLServer),还可以将SQLClient 用于 SQLServer。

这是一个用于 SQLProvider 的 postgres dvdrental(示例)数据库示例:

#r @"..\packages\SQLProvider.1.0.33\lib\FSharp.Data.SqlProvider.dll"
#r @"..\packages\Npgsql.3.1.8\lib\net451\Npgsql.dll"

open System
open FSharp.Data.Sql
open Npgsql
open NpgsqlTypes
open System.Linq
open System.Xml
open System.IO
open System.Data

let [<Literal>] dbVendor = Common.DatabaseProviderTypes.POSTGRESQL
let [<Literal>] connString1  = @"Server=localhost;Database=dvdrental;User Id=postgres;Password=root"
let [<Literal>] resPath = @"C:\Users\userName\Documents\Visual Studio 2015\Projects\Postgre2\packages\Npgsql.3.1.8\lib\net451"
let [<Literal>] indivAmount = 1000
let [<Literal>] useOptTypes  = true

//create the type for the database, based on the connection string, etc. parameters
type sql =  SqlDataProvider<dbVendor,connString1,"",resPath,indivAmount,useOptTypes>
//set up the datacontext, ideally you would use `use` here :-)
let ctx = sql.GetDataContext()
let actorTbl = ctx.Public.Actor //alias the table

//set up the type, in this case  Records:
type ActorName = {
    firstName:string
    lastName:string}

//extract the data with a query expression, this gives you type safety and intellisense over SQL (but also see the SqlClient type provider above):
let qry = query {
            for row in actorTbl do
            select ({firstName=row.FirstName;lastName=row.LastName})
                } 
//seq is lazy so do all kinds of transformations if necessary then manifest it into a list or array:
qry  |> Seq.toArray

两个重要的部分是定义 Actor 记录,然后在查询中将字段提取到 Actor 记录序列中。如有必要,您可以随后显示为列表或数组。

但您也可以坚持原来的解决方案。在这种情况下,只需将.Read() 包装成seq

先定义类型:

type User = {
    floresID: string
    exName: string 
    exPass: string
}

然后提取数据:

let recs = cmd.ExecuteReader() // execute the SQL Command
//extract the users into a sequence of records:
let users = 
    seq {
         while recs.Read() do
             yield {floresID=recs.[0].ToString()
                    exName=recs.[1].ToString()
                    exPass=recs.[2].ToString()
                   }
        } |> Seq.toArray

【讨论】:

    【解决方案2】:

    获取您的代码,您可以使用列表表达式:

    let getUsers =
        use connection = openConnection()
        let getString = "select * from Accounts"
        use sqlCommand = new SqlCommand(getString, connection)
        try
            [
                use reader = sqlCommand.ExecuteReader()
                while reader.Read() do
                    let floresID = reader.GetString 0
                    let exName = reader.GetString 1
                    let exPass = reader.GetString 2
                    let user = [floresID=floresID; exName=exName; exPass=exPass]
                    yield user
            ]
        with
            | :? SqlException as e -> failwithf "Došlo k chybě úrovni připojení:\n %s" e.Message
            | _ -> failwithf "Neznámá výjimka."
    

    话虽如此,我会使用 FSharp.Data.SqlClient 库,所以所有样板代码都变成了一行,并增加了类型安全的好处(如果您更改查询,代码将出现编译时错误,这是显而易见的修复)。

    【讨论】:

      猜你喜欢
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      相关资源
      最近更新 更多