У меня есть sql база данных, содержащая таблицу связей между различными точками. Теперь я хочу найти все точки, которые так или иначе связаны с данной точкой. Я хочу получить полное дерево соединений. Я реализовал класс Node, который содержит точку и ее входы и выходы (другие точки). Метод GetContainedTree (List connectionsTable, int initialPoint) использует connectionTable, чтобы найти все подключенные точки и вернуть их в качестве узла.
public class Connection
{
public int SourcePoint { get; set; }
public int DestinationPoint { get; set; }
}
public class Node
{
public int Point { get; set; }
public List<int> Inputs { get; set; }
public List<int> Outputs { get; set; }
public override string ToString()
{
string desc = "Name: " + Point + "\n";
desc += "\nInputs:\n";
foreach(int i in Inputs)
{
desc += i.ToString() + "\n";
}
desc += "\nOutputs:\n";
foreach (int o in Outputs)
{
desc += o.ToString() + "\n";
}
return desc;
}
}
class Program
{
static void Main(string[] args)
{
List<Connection> connectionTable = new List<Connection>();
// connection tree on
connectionTable.Add(new Connection() { SourcePoint = 1, DestinationPoint = 2 });
connectionTable.Add(new Connection() { SourcePoint = 1, DestinationPoint = 3 });
connectionTable.Add(new Connection() { SourcePoint = 3, DestinationPoint = 4 });
connectionTable.Add(new Connection() { SourcePoint = 2, DestinationPoint = 4 });
connectionTable.Add(new Connection() { SourcePoint = 4, DestinationPoint = 5 });
// connection tree two
connectionTable.Add(new Connection() { SourcePoint = 6, DestinationPoint = 7 });
connectionTable.Add(new Connection() { SourcePoint = 7, DestinationPoint = 8 });
connectionTable.Add(new Connection() { SourcePoint = 7, DestinationPoint = 9 });
connectionTable.Add(new Connection() { SourcePoint = 7, DestinationPoint = 10 });
connectionTable.Add(new Connection() { SourcePoint = 9, DestinationPoint = 11 });
List<Node> tree1 = GetContainingTree(connectionTable, 4);
List<Node> tree2 = GetContainingTree(connectionTable, 11);
Console.WriteLine("Tree One:");
foreach(Node n in tree1)
{
Console.WriteLine(n);
}
Console.WriteLine("Tree Two:");
foreach (Node n in tree2)
{
Console.WriteLine(n);
}
}
private static List<Node> GetContainingTree(List<Connection> connectionsTable, int startingPoint)
{
List<int> pointsToSearch = new List<int>() { startingPoint };
List<Node> nodes = new List<Node>();
while(pointsToSearch!=null && pointsToSearch.Count>0)
{
foreach(int pointToSearch in pointsToSearch)
{
Node node = new Node() { Point = pointToSearch };
// search for outputs
var outputs = from connection in connectionsTable
where connection.SourcePoint == pointToSearch
select connection.DestinationPoint;
// search for inputs
var inputs = from connection in connectionsTable
where connection.DestinationPoint == pointToSearch
select connection.SourcePoint;
node.Inputs = inputs.ToList(); // execute the query on db server
node.Outputs = outputs.ToList(); // execute the query on db server
nodes.Add(node);
}
// update the pointsToSearch
var allPointsInNodes = nodes.SelectMany(n => n.Inputs);
allPointsInNodes.Union(nodes.SelectMany(n => n.Outputs));
// remove all found node names
pointsToSearch = allPointsInNodes.Where(p => !nodes.Select(n => n.Point).ToList().Contains(p))
.Distinct()
.ToList();
}
return nodes;
}
}
Вывод:
Tree One:
Name: 4
Inputs:
3
2
Outputs:
5
Name: 3
Inputs:
1
Outputs:
4
Name: 2
Inputs:
1
Outputs:
4
Name: 1
Inputs:
Outputs:
2
3
Tree Two:
Name: 11
Inputs:
9
Outputs:
Name: 9
Inputs:
7
Outputs:
11
Name: 7
Inputs:
6
Outputs:
8
9
10
Name: 6
Inputs:
Outputs:
7
Мое решение работает, но оно использует много индивидуально выполненных запросов к базе данных. Я хотел бы объединить как можно больше этих запросов, чтобы добиться большей производительности. Есть ли способ объединить логи c GetContainedTree (...) в один запрос? Мне все равно, нужно ли использовать синтаксис запроса или метода.
Я думаю, что было бы возможно объединить этот запрос с серверной функцией на сервере sql, но я хочу оставить свободу для изменения мой движок базы данных позже.
Большое спасибо!