De Données SQL Hiérarchie
J'ai regardé à travers quelques SQL hiérarchie des tutoriels, mais aucun d'entre eux fait beaucoup de sens pour mon application. Peut-être que je suis juste de ne pas les comprendre correctement. Je suis en train d'écrire un C# ASP.NET application et je voudrais créer une arborescence de la hiérarchie à partir de données SQL.
C'est comment la hiérarchie de travail:
TABLE SQL ID | identificateur de Localisation | Nom _______| __________ |_____________ 1331 | 1331 | Maison 1321 | 1331 | Salle 2141 | 1321 | Lit 1251 | 2231 | salle de sport
Si l'ID et le code d'Emplacement sont les mêmes, cela permettrait de déterminer la société Mère. Enfants que les Parents ont le même Emplacement ID en tant que Parent. Tout-petits-enfants de cet Enfant aurait un Emplacement ID égal à l'ID de l'Enfant, et ainsi de suite.
Pour l'exemple ci-dessus:
- Maison -- Salle --- Lit
De l'aide ou de la direction de facile à suivre des tutoriels serait grandement apprécié.
EDIT:
Code que j'ai à ce jour, mais il n'obtient que le Parent et les Enfants, pas de petits-enfants. Je n'arrive pas à comprendre comment le faire de manière récursive obtenir tous les nœuds.
using System;
using System.Data;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.Data.SqlClient;
namespace TreeViewProject
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
PopulateTree(SampleTreeView);
}
public void PopulateTree(Control ctl)
{
//Data Connection
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["AssetWhereConnectionString1"].ConnectionString);
connection.Open();
//SQL Commands
string getLocations = "SELECT ID, LocationID, Name FROM dbo.Locations";
SqlDataAdapter adapter = new SqlDataAdapter(getLocations, connection);
DataTable locations = new DataTable();
//Fill Data Table with SQL Locations Table
adapter.Fill(locations);
//Setup a row index
DataRow[] myRows;
myRows = locations.Select();
//Create an instance of the tree
TreeView t1 = new TreeView();
//Assign the tree to the control
t1 = (TreeView)ctl;
//Clear any exisiting nodes
t1.Nodes.Clear();
//BUILD THE TREE!
for (int p = 0; p < myRows.Length; p++)
{
//Get Parent Node
if ((Guid)myRows[p]["ID"] == (Guid)myRows[p]["LocationID"])
{
//Create Parent Node
TreeNode parentNode = new TreeNode();
parentNode.Text = (string)myRows[p]["Name"];
t1.Nodes.Add(parentNode);
//Get Child Node
for (int c = 0; c < myRows.Length; c++)
{
if ((Guid)myRows[p]["LocationID"] == (Guid)myRows[c]["LocationID"]
&& (Guid)myRows[p]["LocationID"] != (Guid)myRows[c]["ID"] /* Exclude Parent */)
{
//Create Child Node
TreeNode childNode = new TreeNode();
childNode.Text = (string)myRows[c]["Name"];
parentNode.ChildNodes.Add(childNode);
}
}
}
}
//ALL DONE BUILDING!
//Close the Data Connection
connection.Close();
}
}
}
Ici est un snippit de la table SQL: les Lieux
ID LocationID Nom ____________________________________ ____________________________________ ______________ DEAF3FFF-FD33-4ECF-910B-1B07DF192074 48700BC6-la d422-4B26-B123-31A7CB704B97 Drop F 48700BC6-la d422-4B26-B123-31A7CB704B97 7EBDF61C-3425-46DB-A4D5-686E91FD0832 Olway 06B49351-6D18-4595-8228-356253CF45FF 6E8C65AC-CB22-42DA-89EB-D81C5ED0BBD0 Drop E 5 E98BC1F6-4BAE-4022-86A5-43BBEE2BA6CD DEAF3FFF-FD33-4ECF-910B-1B07DF192074 Drop F 6 F6A2CF99-F708-4C61-8154-4C04A38ADDC6 7EBDF61C-3425-46DB-A4D5-686E91FD0832 Pree 0EC89A67-D74A-4A3B-8E03-4E7AAAFEBE51 6E8C65AC-CB22-42DA-89EB-D81C5ED0BBD0 Chute de E 4 35540B7A-62F9-487F-B65B-4EA5F42AD88A 48700BC6-la d422-4B26-B123-31A7CB704B97 Olway Ventilation 5000AB9D-EB95-48E3-B5C0-547F5DA06FC6 6E8C65AC-CB22-42DA-89EB-D81C5ED0BBD0 1 53CDD540-19BC-4BC2-8612 CONNECTEZ-5C0663B7FDA5 6E8C65AC-CB22-42DA-89EB-D81C5ED0BBD0 Drop E 3 7EBDF61C-3425-46DB-A4D5-686E91FD0821 B46C7305-18B1-4499-9E1C-7B6FDE786CD6 TEST 1 7EBDF61C-3425-46DB-A4D5-686E91FD0832 7EBDF61C-3425-46DB-A4D5-686E91FD0832 RÉSEAU
Grâce.
- Ces noms sont source de confusion. Je voudrais changer
Location ID
àParent_ID
. - Un pur SQL réponse peuvent avoir besoin de connaître la version de SQL que vous utilisez. Pouvez-vous indiquez la base de données que vous avez? SQL Server 2008, peut-être?
- Malheureusement je ne peux pas changer les noms de beaucoup trop d'autres choses qui en dépendent. Je suis à l'aide de SQL Server 2008.
- Vous utilisez les types de données HierarchyID?
Vous devez vous connecter pour publier un commentaire.
Vous êtes à la recherche pour une requête récursive à l'aide d'une expression de table commune, ou CTE, pour faire court. Détail écriture-up pour dans SQL Server 2008 peut être trouvé sur le site MSDN.
En général, elles ont une structure semblable à la suivante:
Lorsque cela s'exécute, SQL Server va faire quelque chose de similaire à la suivante (paraphrasé dans un langage plus simple de la MSDN):
Pour cet exemple précis, essayez quelque chose comme ceci:
Compte tenu de vos données d'exemple, vous devriez obtenir quelque chose comme ceci:
Noter que le "Gym" est exclu. Basé sur vos données d'échantillonnage, c'est l'ID ne correspond pas à son [Emplacement ID], de sorte qu'il ne serait pas au niveau de la racine de l'élément. C'est l'endroit ID, 2231, n'apparaît pas dans la liste de validité parent Id.
Edit 1:
Vous avez demandé à propos de l'obtention de ce en C# structure de données. Il y a beaucoup, beaucoup de manières différentes de représenter une hiérarchie dans C#. Voici un exemple, choisi pour sa simplicité. Un véritable exemple de code serait sans doute plus vaste.
La première étape est de définir ce que chaque nœud de la hiérarchie ressemble. D'ailleurs qui contient les propriétés de chaque donnée dans le nœud, j'ai inclus
Parent
etChildren
propriétés, en plus de méthodes pourAdd
un enfant et deGet
un enfant. LeGet
méthode de recherche le nœud de l'ensemble de l'axe descendant, et pas seulement le nœud de ses propres enfants.Maintenant, vous aurez envie de remplir votre arbre. Vous avez un problème ici: il est difficile de remplir un arbre dans le mauvais ordre. Avant d'ajouter un nœud enfant, vous avez vraiment besoin d'une référence au nœud parent. Si vous ont à le faire sortir de la commande, vous pouvez atténuer le problème en deux passes (une pour créer tous les nœuds, puis un autre à la création de l'arbre). Toutefois, dans ce cas, c'est unnecessay.
Si vous prenez la requête SQL que j'ai fournis ci-dessus et de l'ordre par le
depth
colonne, vous pouvez être mathématiquement certain que vous ne serez jamais rencontrez un nœud enfant avant de rencontrer son nœud parent. Par conséquent, vous pouvez le faire en un seul passage.Vous aurez toujours besoin d'un nœud à servir comme la "racine" de votre arbre. Vous obtenez de décider si ce sera de la "Maison" (à partir de votre exemple), ou si c'est une fiction de l'espace réservé nœud que vous créez juste pour ce but. Je propose au plus tard.
Donc, pour le code! Encore une fois, c'est optimisée pour des raisons de simplicité et de lisibilité. Il y a quelques problèmes de performances que vous souhaitez à l'adresse dans le code de production (par exemple, il n'est pas vraiment nécessaire de constamment rechercher la "mère" de nœud). J'ai évité ces optimisations ici, car elles augmentent la complexité.
Ta-da! Le
root
LocationNode contient maintenant l'ensemble de votre hiérarchie. En passant, je n'ai pas réellement exécuté ce code, de sorte s'il vous plaît laissez-moi savoir si vous repérez une flagrante questions.Edit 2
De fixer votre exemple de code, de faire ces changements:
Supprimer cette ligne:
Cette ligne n'est pas vraiment un problème, mais il doit être supprimé. Vos commentaires ici sont inexacts; vous n'êtes pas vraiment l'affectation d'un arbre pour le contrôle. Au lieu de cela, vous êtes la création d'une nouvelle Arborescence, en les confiant à
t1
, puis immédiatement à l'affectation d'un objet différent det1
. L'Arborescence que vous créez est perdu dès que la ligne suivante s'exécute.Fixer votre instruction SQL
Remplacer cette instruction SQL avec l'instruction SQL que j'ai suggéré plus tôt, avec une clause ORDER BY. Lire mon édition précédente qui explique pourquoi la "profondeur" est important: vous avez vraiment ne voulez ajouter les nœuds dans un ordre particulier. Vous ne pouvez pas ajouter un nœud enfant jusqu'à ce que vous avez le nœud parent.
Éventuellement, je pense que vous n'avez pas besoin de la surcharge d'un SqlDataAdapter et DataTable ici. Le DataReader solution que j'ai initialement proposé est plus simple, plus facile à travailler, et plus efficace en termes de ressources.
Aussi, la plupart des C# SQL objets de mettre en œuvre
IDisposable
, de sorte que vous voulez vous assurer que vous utilisez correctement. Si quelque chose vous met en œuvreIDisposable
, être sûr que vous enveloppez-le deusing
consolidés (voir mon précédent exemple de code C#).Fixer votre arbre de construction de la boucle
Vous obtenez seulement les nœuds parents et enfants parce que vous avez une boucle pour les parents et une boucle intérieure pour les enfants. Comme vous devez déjà le savoir, vous n'obtenez pas les petits-enfants parce que vous n'avez pas de code qui ajoute.
Vous pouvez ajouter l'intérieur de la boucle interne pour obtenir les petits-enfants, mais il est clair que vous êtes en demandant de l'aide parce que vous avez rendu compte que cela ne fera que conduire à la folie. Qu'arriverait-il si vous voulais l'arrière-petits-enfants? Un intérieur-intérieur de la boucle interne? Cette technique n'est pas viable.
Vous avez probablement pensé de récursion. C'est un endroit parfait pour elle, et si vous travaillez avec des structures arborescentes, il va venir par la suite. Maintenant que vous avez édité votre question, il est clair que votre problème a peu, sinon rien, à voir avec SQL. Votre vrai problème, c'est avec la récursivité. Quelqu'un peut éventuellement venir et de concevoir une solution récursive pour cela. Que serait parfaitement valable, et éventuellement préférable.
Cependant, ma réponse n'a pas déjà couvert la partie récursive, il a simplement déplacé dans le SQL de la couche. Donc, je vais garder mon code précédent autour, je la sens, c'est un générique de répondre à la question. Pour votre situation spécifique, vous aurez besoin de faire quelques modifications.
Tout d'abord, vous n'avez pas besoin de
LocationNode
classe que j'ai suggéré. Vous utilisezTreeNode
au lieu de cela, et qui fonctionnent bien.Deuxièmement, la
TreeView.FindNode
est similaire à laLocationNode.Get
méthode que j'ai proposé, sauf queFindNode
exige le chemin d'accès complet vers le nœud. Pour utiliserFindNode
, vous devez modifier le SQL pour vous donner cette information.Par conséquent, l'ensemble de votre
PopulateTree
fonction devrait ressembler à ceci:S'il vous plaît laissez-moi savoir si vous trouvez des erreurs supplémentaires!
'var parent = root.Get(id) ?? root;
devriez être en utilisant le code d'Emplacement, pas le courant ID:var parent = root.Get(rs.GetInt32(1)) ?? root;
Je vous recommande également de prendre un coup d'oeil à HierarchyId type de données introduites dans SQL Server 2008 qui vous donne beaucoup de capacités pour la traversée et de la manipulation de la structure de l'arbre. Voici un tutoriel:
Le travail Avec SQL Server HierarchyId Type De Données .NET Application
Désolé, je suis juste une sorte de navigation sur StackOverflow. J'ai vu votre question, et je me sens comme je l'ai écrit un article pour répondre à votre question il y a trois ans. S'il vous plaît laissez-moi savoir si cela aide.
http://www.simple-talk.com/dotnet/asp.net/rendering-hierarchical-data-with-the-treeview/
Il y a une nouvelle fonctionnalité de SQl 2008. C'est hierarchyid. Cette fonctionnalité me rendre la vie plus facile.
Il est utile méthode pour hierarchyid type de données, GetAncestor(), GetRoot()...
Il permettra de réduire la complexité de la requête une fois que je travail sur la hiérarchie.