ADO.NET
2020-12-13 02:20
标签:style tar ext int http get ADO.NET 关系型数据库管理系统(Relational database management systems,RDBMSs)是数据存储最普遍的形式。有了 ADO.NET,System.Data 和相关的命名空间,访问关系型数据更容易。这一节,我们将学习多种方法在F# 中使用 ADO.NET。 注意 所有的数据库提供程序都使用连接字符串指定数据库连接。在http://www.connectionstrings.com 上有关于连接字符串的汇总。 这一节的所有例子都使用 SQL Server 2005 Express Edition 和 AdventureWorks 数据库,两个都可以从http://www.microsoft.com 自由下载;把这些例子导出到其他关系型数据库也是很容易的。要在 SQL Server 2005 Express Edition 中使用这个数据库,需要下面的连接设置,或者根据你的系统作相应调整: name="MyConnection" connectionString=" Database=AdventureWorks; Server=.\SQLExpress; Integrated Security=SSPI; AttachDbFilename= C:\ProgramFiles\Microsoft SQL Server\MSSQL.1\MSSQL\Data\AdventureWorks_Data.mdf" providerName="System.Data.SqlClient" /> [ 上面的配置文件缺少根结点: 用下面的连接字符串也可以: name="MyConnection" connectionString=" DataSource=.\sqlexpress; InitialCatalog=AdventureWorks; IntegratedSecurity=True; Pooling=False" providerName=".NET Framework Data Providerfor SQL Server" /> ] 我们将在“ADO.NET 扩展”一节讨论访问其他关系型数据库的选项。下面的例子演示了访问数据库的一种简单方法: open System.Configuration open System.Data open System.Data.SqlClient // get the connection string let connectionString = letconnectionSetting = ConfigurationManager.ConnectionStrings.["MyConnection"] connectionSetting.ConnectionString let main() = //create a connection useconnection = new SqlConnection(connectionString) //create a command letcommand = connection.CreateCommand(CommandText= "select * from Person.Contact", CommandType =CommandType.Text) //open the connection connection.Open() //open a reader to read data from the DB usereader = command.ExecuteReader() //fetch the ordinals lettitle = reader.GetOrdinal("Title") letfirstName = reader.GetOrdinal("FirstName") letlastName = reader.GetOrdinal("LastName") //function to read strings from the data reader letgetString (r: #IDataReader) x = if r.IsDBNull(x) then "" else r.GetString(x) //read all the items while reader.Read() do printfn "%s %s %s" (getString reader title ) (getString reader firstName) (getString reader lastName) main() 前面代码的运行结果如下: Mr. Gustavo Achong Ms. Catherine Abel Ms. Kim Abercrombie Sr. Humberto Acevedo Sra. Pilar Ackerman Ms. Frances Adams Ms. Margaret Smith ... 在前面的例子中,首先看到的是将要用到的连接字符串;之后,就创建连接: using (new SqlConnection(connectionString)) 注意,我们使用 use 关键字代替 let,这是保证在完成所做工作之后,能够关闭连接;use 关键字能够保证当连接超出其作用域后,会调用Dispose 方法。然后,使用连接创建 SqlCommand 类,再设置它的 CommandText 属性,指定需要执行的命令: let command = connection.CreateCommand(CommandText = "select * fromPerson.Contact", CommandType =CommandType.Text) 接下来,执行这个命令创建 SqlDataReader 类,用这个类读数据库: use reader = command.ExecuteReader() 这个命令也使用 use 绑定,代替 let,确保可以正确关闭。 如果必须为每个查询写大量的代码,那么,在 F# 中可能并不需要写数据访问的代码。有一个简单的方法,创建执行命令的库函数,这样。就能把使用的连接、运行的命令参数化。 下面的例子演示如何写出这样一个函数,实现 execCommand 函数,使用 Seq.generate,它能产生可枚举的序列集合。generate 函数有三个参数:第一个函数打开到数据库的连接,在每次枚举结果集合时调用,这个函数被称为开启者(opener),也能够用它来打开对文件的连接;第二个函数生成集合中的元素,称为生产者(generator)。这段代码用一行数据创建了字典(Dictionary)对象;第三个函数是用于关闭数据库或读取文件的连接: open System.Configuration open System.Collections.Generic open System.Data open System.Data.SqlClient open System.Data.Common open System /// create and open an SqlConnection objectusing the connection string found /// in the configuration file for the givenconnection name let openSQLConnection(connName:string) = letconnSetting = ConfigurationManager.ConnectionStrings.[connName] letconn = new SqlConnection(connSetting.ConnectionString) conn.Open() conn /// create and execute a read command for aconnection using /// the connection string found in theconfiguration file /// for the given connection name let openConnectionReader connName cmdString= letconn = openSQLConnection(connName) letcmd = conn.CreateCommand(CommandText=cmdString, CommandType =CommandType.Text) letreader = cmd.ExecuteReader(CommandBehavior.CloseConnection) reader /// read a row from the data reader let readOneRow (reader: #DbDataReader) = ifreader.Read() then letdict = new Dictionary forx in [ 0 .. (reader.FieldCount - 1) ] do dict.Add(reader.GetName(x), reader.[x]) Some(dict) else None /// execute a command using theSeq.generate let execCommand (connName: string)(cmdString: string) = Seq.generate //This function gets called to open a connection and create a reader (fun () -> openConnectionReader connNamecmdString) //This function gets called to read a single item in //the enumerable for a reader/connection pair (fun reader -> readOneRow(reader)) (fun reader -> reader.Dispose()) [ 以下的两段出现在这里,重复。 已经在后面单独出现了。 ] /// open the contacts table let contactsTable = execCommand "MyConnection" "select* from Person.Contact" /// print out the data retrieved from thedatabase for row in contactsTable do forcol in row.Keys do printfn"%s = %O" col (row.Item(col)) [ 除 System.Configuration、System.Data 以外,还需要 Fsharp.PowerPack ] 定义了execCommand 函数之后,再访问数据库就变得非常容易了。调用 execCommand,把需要的连接和命令作为参数传入,然后,枚举结果。就如下面的示例: let contactsTable = execCommand "MyConnection" "select * from Person.Contact" for row in contactsTable do for col in row.Keys do printfn "%s = %O" col(row.Item(col)) 运行结果如下: ... ContactID = 18 NameStyle = False Title = Ms. FirstName = Anna MiddleName = A. LastName = Albright Suffix = EmailAddress = anna0@adventure-works.com EmailPromotion = 1 Phone = 197-555-0143 PasswordHash =6Hwr3vf9bo8CYMDbLuUt78TXCr182Vf8Zf0+uil0ANw= PasswordSalt = SPfSr+w= AdditionalContactInfo = rowguid =b6e43a72-8f5f-4525-b4c0-ee84d764e86f ModifiedDate = 01/07/2002 00:00:00 ... 有一件事情必须注意,处理关系型数据库时,需要保证连接及时关闭。很快地关闭连接,可以使连接用于其他数据库用户,提高并行访问能力。我们看一下前面的例子,看它是如何创建连接,并自动清除的。在前面的例子中,开启者在每次使用Seq.iter 枚举集合时调用函数 openConnectionReader;它使用可枚举对象遍历数据,重复使用生产者函数产生单独的结果。每次调用 Seq.iter 就创建一个SqlConnection [ 不应该是SqlDataReader ]和 SqlDataReader 对象。在遍历结束时,或者由于某些原因遍历突然终止时,这些对象必须关闭。幸运的是,Seq.generate
函数能够在遍历完成或部分完成时,清除资源。当客户端完成枚举集合时,就调用关闭函数。应该使用这个函数在SqlDataReader上调用 IDisposable.Dispose 方法,触发关闭。还必须关闭对应的 SqlConnection 对象,它是由关闭 SqlDataReader、再关闭数据库连接而完成的。 command.ExecuteReader(CommandBehavior.CloseConnection) 为不使连接打开时间太长,应该在遍历可枚举集合的结果期间,避免复杂或过度耗时的操作,特别要避免用户与集合因某种原因的交互。例如,下面的代码重写了前面的例子,用户通过按回车键移动到下一条记录,这对数据库的性能是有害的: for row in contactsTable do for col in row.Keys do printfn "%s = %O" col(row.Item(col)) printfn "Press read_line() |> ignore 如果你想多次使用集合,或者想让用户交互,通常应该把它转换成列表或数组,就像下面的代码: let contactsTable = execCommand "select * from Person.Contact" "MyConnection" let contactsList = Seq.toList contactsTable 虽然当游标被垃圾回收时,连接将被关闭,但这个过程通常要花很长时间,特别是系统在高压力下。例如,如果写的代码运行服务器应用程序,处理大量并发用户,那么,不关闭连接将引起错误,因为服务器会很快用完数据库连接。 ADO.NET,搜素材,soscw.com ADO.NET 标签:style tar ext int http get 原文地址:http://blog.csdn.net/hadstj/article/details/25315383