Search code examples
ado.netf#treedatarelation

F# Navigate object graph to return specific Nodes


I'm trying to build a list of DataTables based on DataRelations in a DataSet, where the tables returned are only included by their relationships with each other, knowing each end of the chain in advance. Such that my DataSet has 7 Tables. The relationships look like this:

Table1 -> Table2 -> Table3 -> Table4 -> Table5
                           -> Table6 -> Table7

So given Table1 and Table7, I want to return Tables 1, 2, 3, 6, 7

My code so far traverses all the relations and returns all Tables so in the example it returns Table4 and Table5 as well. I've passed in the first, last as arguments, and know that I'm not yet using the last one yet, I am still trying to think how to go about it, and is where I need the help.

type DataItem =
    | T of DataTable
    | R of DataRelation list

let GetRelatedTables (first, last) =
    let rec flat_rec dt acc =
        match dt with
        | T(dt)   -> 
            let rels = [ for r in dt.ParentRelations do yield r ]
            dt :: flat_rec(R(rels)) acc             
        | R(h::t) -> 
            flat_rec(R(t)) acc @ flat_rec(T(h.ParentTable)) acc
        | R([])   -> []
    flat_rec first []

Solution

  • I think something like this would do it (although I haven't tested it). It returns DataTable list option because, in theory, a path between two tables might not exist.

    let findPathBetweenTables (table1 : DataTable) (table2 : DataTable) =
        let visited = System.Collections.Generic.HashSet() //check for circular references
        let rec search path =
            let table = List.head path
            if not (visited.Add(table)) then None
            elif table = table2 then Some(List.rev path)
            else 
                table.ChildRelations
                |> Seq.cast<DataRelation>
                |> Seq.tryPick (fun rel -> search (rel.ChildTable::path))
        search [table1]