简体   繁体   English

用类型填充列表

[英]Populate list with Types

Im trying to populate list with my own type. 我试图用我自己的类型填充列表。

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."

In C# I would just add new object into userList . 在C#中,我只是将新对象添加到userList How can I add new user into list? 如何将新user添加到列表中? Or is it better approach to get some sort of list with data from database? 还是从数据库中获取某种包含数据的列表的更好方法?

Easiest way to do this is with a type provider, so you can abstract away the database. 最简单的方法是使用类型提供程序,因此您可以抽象出数据库。 You can use SqlDataConnection for SQLServer, SqlProvider for everything (incl. SQLServer), and also SQLClient for SQLServer. 您可以将SqlDataConnection用于SQLServer,将SqlProvider用于所有内容(包括SQLServer),也可以将SQLClient用于SQLServer。

Here is an example with postgres's dvdrental (sample) database for SQLProvider: 这是用于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

The two important parts are defining the Actor record, and then in the query extracting the fields into a sequence of Actor records. 两个重要部分是定义Actor记录,然后在查询中将字段提取为一系列Actor记录。 You can then manifest into a list or array if necessary. 然后,您可以根据需要将其显示在列表或数组中。

But you can also stick to your original solution. 但是您也可以坚持使用原始解决方案。 In that case just wrap the .Read() into a seq : 在这种情况下,只需将.Read()包装到seq

First define the type: 首先定义类型:

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

Then extract the data: 然后提取数据:

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

Taking your code, you can use list expression: 以您的代码,您可以使用列表表达式:

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."

That being said, I'd use FSharp.Data.SqlClient library so all of that boiler plate becomes a single line with added benefit of type safety (if you change the query, the code will have compile time error which are obvious to fix). 话虽这么说,我会使用FSharp.Data.SqlClient库,以便所有样板都变成单行,并增加了类型安全性(如果您更改查询,代码将具有编译时错误,很明显可以修复) 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM