#sql-server #f# #import #matrix
#sql-сервер #f# #импорт #матрица
Вопрос:
У меня есть следующий код, который выполняет импорт из SQL в F # и преобразует информацию в матрицу.
Здесь у меня есть пример пользователей, имеющих 4 критерия, но если я хочу добавить, например, еще 2 критерия (и количество критериев может измениться) Мне придется сделать это вручную (в этом коде измерение не выполняется автоматически, и должны быть записаны имена столбцов).
Это решение работает, но мне приходится вручную проверять изменения в таблице SQL и вручную изменять имена столбцов в моем коде, что вскоре станет очень болезненным. Итак, мой вопрос :
Видите ли вы способ автоматически учитывать размеры таблицы SQL и, в более общем плане, есть ли у вас способ выполнить этот импорт без необходимости вручную вводить имя каждого столбца («Criteria0_ID» и т. Д. — Это имена столбцов в SQL»)? Заранее спасибо !
type user = {
Criteria0_ID : int;
Criteria1_ID : int;
Criteria2_ID : int;
Criteria3_ID : int}
// Extraction from SQL
module ReadSQl =
let GetUsers = seq {
let connStr = new SqlConnectionStringBuilder(DataSource="localhostsqlexpress", IntegratedSecurity=true, InitialCatalog="TestExtractionF#")
use cnn = new SqlConnection(connStr.ConnectionString)
use cmd = new SqlCommand("SELECT * FROM SyntheseTest", cnn)
cnn.Open()
use reader = cmd.ExecuteReader()
while reader.Read() do
yield {
Criteria0_ID = unbox(reader.["Criteria0_ID"])
Criteria1_ID = unbox(reader.["Criteria1_ID"])
Criteria2_ID = unbox(reader.["Criteria2_ID"])
Criteria3_ID = unbox(reader.["Criteria3_ID"])
}
}
// Sequence transformation
let UserBase = GetUsers |> Seq.toList
// Creating the matrix
let matrixUA =
Matrix.ofList
[ // Create list containing rows from the database
for row in UserBase do
// For each row, return list of columns (float values)
yield [ float row.Criteria0_ID;
float row.Criteria1_ID;
float row.Criteria2_ID;
float row.Criteria3_ID;
] ]
matrixUA
Ответ №1:
Используя FsSql, вы можете написать что-то вроде этого:
let readMatrixUA() =
let connStr = SqlConnectionStringBuilder(DataSource="localhostsqlexpress", IntegratedSecurity=true, InitialCatalog="TestExtractionF#")
use cnn = new SqlConnection(connStr.ConnectionString)
cnn.Open()
Sql.execReader (Sql.withConnection cnn) "select * from SyntheseTest" []
|> Sql.map Sql.asNameValue
|> Seq.map (Seq.map (snd >> Option.fromDBNull >> Option.getOrDefault >> float))
|> Matrix.ofSeq
Комментарии:
1. Это может быть очень хорошим ответом, у меня просто ошибка, которую я не понимаю: ExecuteReader требуется открытое и доступное соединение. Соединение фактически закрыто. Эта ошибка, похоже, относится к C:prgFsSqlFsSqlFsSql.fs:line 193 и C:prgFsSqlFsSqlFsSql.fs:line 203.
2. @katter75 : я забыл открыть соединение. Отредактировал мой ответ, чтобы исправить это.
3. Да, спасибо, я исправил это, теперь появляется новая ошибка: указанное приведение недопустимо (ошибка, похоже, исходит от execReader)
4. @katter75: я не знаю, с каким типом база данных пытается считывать поля. Этот код пытается прочитать их непосредственно как значения с плавающей запятой. Возможно, вы захотите сначала прочитать их как int, а затем преобразовать их в значения с плавающей запятой.
5. @katter75: например, вместо
Seq.cast
doSeq.cast<int> >> Seq.map float
Ответ №2:
В текущей версии F # вам всегда нужно будет определять user
тип самостоятельно. Вы можете сделать несколько трюков, чтобы сделать копирование более приятным. Проще всего использовать ?
оператор для получения следующего синтаксиса:
let (?) (reader:SqlDataReader) (name:string) : 'T =
unbox (reader.[name])
yield { Criteria1_ID = reader?Criteria1_ID
Criteria2_ID = reader?Criteria2_ID
Criteria3_ID = reader?Criteria3_ID }
Вы можете пойти еще дальше — если вы откроете Microsoft.FSharp.Reflection
, вы можете использовать FSharpType.GetRecordFields
, чтобы получить имена полей (используя отражение) и выполнить копирование динамически — если вы используете этот подход, вам нужно будет только изменить объявление записи. Вероятно, это все, что вы можете получить с текущей версией F #.
Однако F # 3.0 (поставляется в Visual Studio 11) содержит функцию, называемую проверкой типов, которая, по сути, позволяет автоматически импортировать схему. Вы можете узнать больше из выступлений Дона Сайма (см., Например, Это) и из документации MSDN (черновик).