Я пытаюсь получить данные из базы данных MySQL.
Подход 2 - применить / стиль карты
Я использую Справочник MySQL ADO, чтобы попытаться построить эту систему. В частности, пример из 21.2.3.1.7.
(с использованием псевдокода)
let table = build_sequence(query.read)
Где query.read возвращает строку в таблице (или, скорее, список элементов, которые оказались строкой в таблице). А переменная таблицы - это список списков, которые будут представлять таблицу, возвращаемую из запроса.
Я смотрел на приведенный ниже код, и, боюсь, его синтаксис не подходит.
Подход 1 - петлевой.
Проблема 1: это неэлегантно, требует изменяемого.
Проблема 2: Это просто чувствует неверно, исходя из моего предыдущего опыта работы с Prolog и Lisp. Должен быть более ... функциональный способ сделать это.
Я не уверен, с чего начать. Комментарии и мысли?
let reader : MySql.Data.MySqlClient.MySqlDataReader = command.ExecuteReader()
let arr = []
let mutable rowIter = 0
let readingLoop() =
while(reader.Read()) do
rowIter = rowIter + 1
for i = 0 to reader.FieldCount do
//set arr[someiterator, i] = reader.GetValue[i].ToString())






Работать с императивными API без императивного выполнения может быть сложно. У меня нет MySql под рукой, но я сделал приближение, надеюсь, это послужит источником вдохновения. Seq.unfold - это функция, которую люди находят довольно классной, когда пробуют ее. List.init (или Array.init) также удобен для инициализации структур данных известного размера без использования изменяемых файлов.
#light
type ThingLikeSqlReader() =
let mutable rowNum = 0
member this.Read() =
if rowNum > 3 then
false
else
rowNum <- rowNum + 1
true
member this.FieldCount = 5
member this.GetValue(i) = i + 1
let reader = new ThingLikeSqlReader()
let data = reader |> Seq.unfold (fun (reader : ThingLikeSqlReader) ->
if reader.Read() then
Some (List.init reader.FieldCount (fun i -> reader.GetValue(i)), reader)
else
None) |> Seq.to_list
printfn "%A" data
Тип Seq имеет удобную функцию для обработки курсоров базы данных, которая называется generate_using (см. F# Руководство и главу о доступе к данным в Основы F#). Это функция более высокого порядка, которая принимает одну функцию для открытия курсора и другую (вызываемую повторно) для обработки записей из курсора. Вот код, который использует generate_using для выполнения sql-запроса:
let openConnection (connectionName : string) =
let connectionSetting = ConfigurationManager.ConnectionStrings.Item(connectionName)
let connectionString = connectionSetting.ConnectionString
let connection = new OracleConnection(connectionString)
connection.Open()
connection
let generator<'a> (reader : IDataReader) =
if reader.Read() then
let t = typeof<'a>
let props = t.GetProperties()
let types = props
|> Seq.map (fun x -> x.PropertyType)
|> Seq.to_array
let cstr = t.GetConstructor(types)
let values = Array.create reader.FieldCount (new obj())
reader.GetValues(values) |> ignore
let values = values
|> Array.map (fun x -> match x with | :? DBNull -> null | _ -> x)
Some (cstr.Invoke(values) :?> 'a)
else
None
let executeSqlReader<'a> (connectionName : string) (sql : string) : 'a list =
let connection = openConnection connectionName
let opener() =
let command = connection.CreateCommand(CommandText = sql, CommandType = CommandType.Text)
command.ExecuteReader()
let result = Seq.to_list(Seq.generate_using opener generator)
connection.Close()
connection.Dispose()
result
Например, чтобы вывести список всех таблиц в базе данных Oracle, нам нужно определить тип определения столбца и вызвать executeSqlReader следующим образом:
type ColumnDefinition = {
TableName : string;
ColumnName : string;
DataType : string;
DataLength : decimal;
}
let tableList = executeSqlReader<ColumnDefinition>
"MyDatabase"
"SELECT t.table_name, column_name, data_type, data_length FROM USER_TABLES t, USER_TAB_COLUMNS c where t.TABLE_NAME = c.table_name order by t.table_name, c.COLUMN_NAME"
Я бы использовал ключевое слово использовать для удаления соединения вместо того, чтобы делать это вручную.
По прошествии времени я все еще не могу разобраться в синтаксисе.
В ПОРЯДКЕ. Я до сих пор не совсем доволен всеми синтаксическими элементами в этом, но я следую семантике, и она отвечает на мой вопрос. Большое Вам спасибо.