2012-02-15 6 views
4

Je suis bloqué pour le moment essayer de trouver une méthode d'insertion dans SQL Server à partir de F #.F # insérer une liste dans SQL Server

J'ai une fonction F # qui itère à travers tous les fichiers dans un dossier suivant un modèle défini par l'utilisateur. Ensuite, je peux utiliser les données retournées pour mettre dans une liste ou (idéalement) insérer dans une base de données.

J'ai déjà un insert en-sql fonction de travail qui fonctionne correctement:

let execNonQuery conn s = 
let comm = 
    new SqlCeCommand(s, conn) 
try 
    comm.ExecuteNonQuery() |> ignore 
with e -> 
    printf "Error : %A\n" e 

let string = "insert into MyTable (MyColumn) values ('test .. again')" 
execNonQuery conn string; // works 

J'essaie d'obtenir que cette méthode fonctionne correctement:

let rec getAllFiles dir pattern = 
    seq { yield! Directory.EnumerateFiles(dir, pattern) 
      for d in Directory.EnumerateDirectories(dir) do 
       yield! getAllFiles d pattern } 

let getApplications (dir : string) (extension : string) = 
    getAllFiles dir extension 
    //|> Seq.toList // If I need to create a list of returned values 
    |> Seq.iter (fun s -> SQLInsertString s) // This does not work as it complains about the function not being of type unit 

Si je Seq.toList seulement et appelez la fonction comme ci-dessous, cela fonctionne:

getApplications "C:\Admin" "*.txt" // works 

L'autre chose que je ne comprends pas est de savoir comment créer une commande d'insertion qui accepte une chaîne pour Value. Par exemple:

let SQLInsertString s = "insert into MyTable (MyColumn) values (%s)" //does not work 

Répondre

4

La meilleure façon de passer des paramètres à une requête est d'utiliser SqlCeParameter. C'est plus facile que de composer des chaînes (parce que vous n'avez pas besoin d'encoder des chaînes et d'échapper des citations) et c'est aussi plus sûr, parce que vous évitez SQL injection attack. Voici un exemple de base:

let sqlInsertString value = 
    // Create and open connection ('use' makes sure it gets closed at the end) 
    use conn = new SqlCeConnection("..."); 
    conn.Open() 
    // Create a command with a parameter named '@str' 
    let cmd = new SqlCeCommand("INSERT INTO MyTable (MyColumn) values (@str)", conn) 
    // Create parameter '@str' with string value 'value' and add it to the command 
    let param = new SqlCeParameter("@str", SqlDbType.NVarChar, value) 
    cmd.Parameters.Add(param) 
    // Now run the command (exception handling omitted) 
    cmd.ExecuteNonQuery() |> ignore 

Cette fonction, vous devriez maintenant être en mesure d'utiliser Seq.iter. La fonction prend un string à insérer et retourne unit (pas de valeur), il peut donc être passé à Seq.iter:

let getApplications (dir : string) (extension : string) = 
    getAllFiles dir extension 
    |> Seq.iter (fun s -> sqlInsertString s) 

Vous pouvez écrire la dernière ligne comme |> Seq.iter sqlInsertString. Si vous faites cela, vous dites essentiellement que l'argument s doit être directement passé à la fonction sqlInsertString.

+0

Merci beaucoup Tomas, fonctionne comme un charme. Maintenant, je m'en occupe mieux aussi –

5

Vous y êtes presque. Le problème est sqlInsertString renvoie string qui n'est pas légal à utiliser dans Seq.iter.

Ce que vous faites avec sqlInsertString consiste à créer une chaîne en utilisant des formats de chaîne. Il convient bien avec sprintf fonction:

let sqlInsertString s = 
    sprintf "insert into MyTable (MyColumn) values (%s)" s 

vous pouvez maintenant utiliser execNonQuery sur les résultats de sqlInsertString pour insérer des données dans la base de données réellement. Depuis execNonQuery retours unit, il pourrait être facilement utilisé dans Seq.iter:

// Assuming conn is a global and already defined variable. 
let getApplications (dir : string) (extension : string) = 
    getAllFiles dir extension 
    |> Seq.iter (fun s -> execNonQuery conn (sqlInsertString s)) 

Depuis l'annotation de type est redondant, votre code pourrait être réécrite d'une manière plus idiomatiques:

let getApplications dir extension conn = 
    getAllFiles dir extension 
    |> Seq.iter (sqlInsertString >> execNonQuery conn) 
+0

Un grand merci pour cela. Cette réponse fonctionne aussi comme un charme. J'ai dû choisir une réponse pour être la réponse comme prévu et Tomas a expliqué comment utiliser les paramètres. –