2010-06-05 21 views
9

Tengo un lector de datos y quiero devolver la colección de filas de él, después de leer libros por un día no puedo encontrar la mejor manera de hacerlo en f #. Puedo hacerlo normal de C# forma en C#, pero eso no es por lo que estoy usando f #F # trabajando con while loop

Esto es lo que estoy tratando de lograr

let values = 
    while reader.Read() do 
     yield reader.GetString(0), reader.GetInt64(1) 

Por encima es como yo estoy tratando de hacer

  • obtener todos los valores recogidos en valores, que podría ser dictinary o tuplas o cualquier colección
  • rendimiento no se puede utilizar en bucle while, pero eso es lo que estoy tratando de hacer

¿Cuál podría ser la mejor manera de lograr esto

Respuesta

13

F # también proporciona comprensión de listas para matrices y secuencias.

let records_as_list = 
    [ 
     while reader.Read() 
      do yield (reader.GetString(0), reader.GetInt64(1)) 
    ] 

let records_as_array = 
    [| 
     while reader.Read() 
      do yield (reader.GetString(0), reader.GetInt64(1)) 
    |] 

let records_as_sequence = 
    seq { 
     while reader.Read() 
      do yield (reader.GetString(0), reader.GetInt64(1)) 
    } 

F # tiene una conveniente función de diccionario integrado en el denominado dict

let records_as_IDictionary = dict records_as_sequence 
7

Se pueden utilizar expresiones de secuencia para implementar enumeradores:

let records = seq { while reader.NextResult() do yield (reader.GetString(0), reader.GetInt64(1)) } 

Si necesita más de dos campos, puede producir mapas de índice de la columna (o nombre) -> valores de campo (código no probado):

let dbSchema = reader.GetSchemaTable() 

let makeMap (rdr : IDataReader) (schema : DataTable) = 
    schema.Columns |> Seq.cast<DataColumn> |> Seq.map (fun col -> (col.ColumnName, rdr.[col.ColumnName])) |> Map.ofSeq 

let records = seq { while reader.NextResult() do yield (makeMap reader dbSchema) } 
+0

Problema con la SEC es que lo hace la carga diferida por lo que cuando se quiere leerlo en este lector caso se cerraría – mamu

+0

puede arreglar fácilmente añadiendo |> Seq.toList a la última fila de materializar la colección. – Mau

3

Para este tipo de tarea, me gustaría transferir primero la entrada a una secuencia de cadenas.

.Net 4.0 proporciona readlines, el tipo de su valor de retorno es seq<string>:

open System.IO 
    let readLinesSeq = File.ReadLines 

En versiones inferiores de .Net, hay que implementar esta función:

let readLines filePath = seq { 
    use sr = new StreamReader (filePath) 
    while not sr.EndOfStream do 
    yield sr.ReadLine() 
    } 
+0

La pregunta es sobre 'System.Data.IDataReader' - no entrada de archivo ... –

+0

@ Joel..Oops ... La idea debería ser similar ... –

+0

Sí, la idea básica es la misma. –

0

bien lo estamos no se trata de archivos aquí, sin embargo, en versiones anteriores de .NET puede hacerlo (con archivos pequeños):

reader.ReadToEnd().Split(System.Environment.NewLine.ToCharArray()) 

Donde reader es un TextReader.

+0

Si el archivo es grande, se debe evitar leer todo el contenido y dividirlo. –

+0

En esta pregunta, 'reader' es en realidad un IDataReader, no un TextReader –

2

podría abordar este problema de manera más genérica mediante la adición de una propiedad de extensión a IDataReader que convierte cualquier datareader en un seq<IDataRecord> ...

[<AutoOpen>] 
module DataReaderEx = 
    open System.Data 

    type IDataReader with 
     member this.toSeq = 
      seq { while this.Read() do yield this :> IDataRecord } 

Esto le permitiría usar funciones ordinarias del Seq módulo en cualquier datareader:

reader.toSeq 
|> Seq.map (fun row -> row.GetString(0), row.GetInt64(1))