Database 如何在F#中使用带IDataReader的字符串索引?
我对F#还不熟悉,试图先深入了解,然后再做更正式的介绍。我有以下代码:Database 如何在F#中使用带IDataReader的字符串索引?,database,sqlite,f#,data-access,idatareader,Database,Sqlite,F#,Data Access,Idatareader,我对F#还不熟悉,试图先深入了解,然后再做更正式的介绍。我有以下代码: type Person = { Id: int Name: string } let GetPeople() = //seq { use conn = new SQLiteConnection(connectionString) use cmd = new SQLiteCommand(sql, conn) cmd.CommandType
type Person =
{
Id: int
Name: string
}
let GetPeople() =
//seq {
use conn = new SQLiteConnection(connectionString)
use cmd = new SQLiteCommand(sql, conn)
cmd.CommandType <- CommandType.Text
conn.Open()
use reader = cmd.ExecuteReader()
let mutable x = {Id = 1; Name = "Mary"; }
while reader.Read() do
let y = 0
// breakpoint here
x <- {
Id = unbox<int>(reader.["id"])
Name = unbox<string>(reader.["name"])
}
x
//}
let y = GetPeople()
根据调试器,id
的类型为object{long}
。您可以在即时窗口中使用reader[“name”]
,因为即时窗口使用C语法,而不是F语法
需要注意的一点是:由于F#比C#简洁得多,因此在一行中可能会发生很多事情。换句话说,在线路上设置断点可能无助于缩小问题范围。在这些情况下,我通常将表达式“扩展”为多行上的多个let绑定;这样做可以更容易地单步遍历表达式并找到问题的原因(此时,您只需更改原始的一行代码即可)
如果将项访问和unbox
调用拉入它们自己的let绑定,会发生什么情况?例如:
while reader.Read() do
let y = 0
// breakpoint here
let id = reader.["id"]
let id_unboxed : int = unbox id
let name = reader.["name"]
let name_unboxed : string = unbox name
x <- { Id = id_unboxed; Name = name_unboxed; }
x
当reader.Read()执行以下操作时
设y=0
//断点在这里
let id=读卡器。[“id”]
let id_unbox:int=unbox id
让name=读取器。[“name”]
let name_unbox:string=unbox name
Jack已经回答了关于F#和immediate window或watchs中索引的不同语法的问题,所以我将跳过这个问题 根据我的经验,从数据库读取数据时获取
System.InvalidCastException
最常见的原因是reader.[“xyz”]
返回的值实际上是DbNull.value
而不是实际的字符串或整数。将DbNull.Value
强制转换为整数或字符串将失败(因为它是一个特殊值),因此,如果使用的是可为null的列,则需要明确检查:
let name = reader.["name"]
let name_unboxed : string =
if name = DbNull.Value then null else unbox name
通过定义?
运算符,可以编写reader?name
来执行查找,从而使代码更加美观。如果您处理的是空值,还可以使用以下定义的reader?name defaultValue
:
let (?) (reader:IDataReader) (name:string) (def:'R) : 'R =
let v = reader.[name]
if Object.Equals(v, DBNull.Value) then def
else unbox v
然后,代码变为:
let name = reader?name null
let id = reader?id -1
这还可以简化调试,因为您可以逐步实现
?
,并查看发生了什么。这很有帮助。行let id_unbox=unbox id
有错误。在调试器中查看id
的类型,它会显示对象{long}
。在即时窗口中,id为long
返回true,而id为int
返回false。所以我猜这和整型和长型铸造有关。将进一步试验。@User如果它是长的
,则需要将其作为int64
(F#语法为长的
)。我认为您需要将其取消装箱到正确的类型(int64
),然后将其强制转换为int
,如果这是您需要的--您不能直接取消装箱(这导致了您现在看到的错误)。如果我将我的个人类型更改为使用int64
,而不是int
,则可以正常工作。不确定它为什么要从db中拖出这么长的id。刚刚发现SQLite使用int64作为整数主键,因此可以解释:
let name = reader?name null
let id = reader?id -1