1

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 []
Calvin
  • 423
  • 3
  • 12

1 Answers1

1

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]
Daniel
  • 47,404
  • 11
  • 101
  • 179
  • OK. That works like a charm! Though the traversal is going the other way, down through the children, which I suppose isn't an issue, if the result is the same. I will try some more scenarios to test it, like self referential tables or such things, but great. Thanks a lot! – Calvin Jul 18 '14 at 18:49
  • You're welcome. You could easily change it to go the other way if you prefer. It should handle self-referencing tables fine. – Daniel Jul 18 '14 at 18:56
  • BTW, thought it might be worth pointing out this is just a special case of [DFS](http://en.wikipedia.org/wiki/Depth-first_search). [BFS](http://en.wikipedia.org/wiki/Breadth-first_search) might be more efficient for this problem, but DFS is slightly easier to implement. – Daniel Jul 18 '14 at 19:00
  • It does indeed, both. I was looking at those earlier and would certainly benefit from more reading, which I'll add to the list. Thanks again. – Calvin Jul 18 '14 at 19:13