General conversion of an array of records into a DataTable and vice versa in F #

I have a simple array of F # entries of the following type (or some minor variations based on system types):

type Transaction= { date: DateTime; amount: float; mutable details: string } 

I would like to display them in a DataGridView control in Winforms, including support for modifying content and adding or removing rows / records. Binding a DataViewGrid to an array of records does not seem to allow rows to be added / removed (or should I do it wrong?). However, DataTable structures are better suited for this purpose. Creating a DataTable of the specified type seems to be consistent with the original type of the record, for example.

 let dataTable = new DataTable() dataTable.Columns.Add("date", typeof<DateTime>) |> ignore dataTable.Columns.Add("amount", typeof<float>) |> ignore dataTable.Columns.Add("details", typeof<string>) |> ignore) 

So, I wonder if there is an existing system function for converting an array of records (for example, of the "transaction array" type) for any type of records based on the types of the system into the corresponding DataTable and vice versa? If there is no such function, how can this be done in a concise form?

+4
source share
1 answer

There is no built-in function for this.

The most straightforward way to implement the conversion is to use F # reflection, but the naive use of reflection (like this) can be quite slow, so you need to evaluate if there is enough performance for what you are trying to do (if this is one change to display things in the user interface than this is probably fine).

Here is a sketch of how you could do this:

 open Microsoft.FSharp.Reflection let recordsToDataTable (items:'T list) = // Create data table and add fields based on the record type let dataTable = new DataTable() let fields = FSharpType.GetRecordFields(typeof<'T>) for fld in fields do dataTable.Columns.Add(fld.Name, fld.PropertyType) |> ignore // Add values from the specified list to the table for itm in items do let row = dataTable.NewRow() // Set all fields of the current row for fld in fields do row.[fld.Name] <- fld.GetValue(itm) dataTable.Rows.Add(row) dataTable let dataTableToRecords (table:DataTable) : 'T list = let fields = FSharpType.GetRecordFields(typeof<'T>) // Create a list with item for every row in the table [ for row in table.Rows -> // Get values of all fields from DT and create a record value let values = [| for fld in fields -> row.[fld.Name] |] FSharpValue.MakeRecord(typeof<'T>, values) :?> 'T ] 
+9
source

Source: https://habr.com/ru/post/1437950/


All Articles