[C#/MSSQL] Relacje z funkcji SQL

0

Witam.
W SQL napisana jest funkcja przyjmująca jeden parament i zwracająca tabelę wyników.

Struktura funkcji:

CREATE  FUNCTION [CDN].[TwrGrupy] (@GIDNumer INT)
RETURNS @TwrGrupy TABLE (TwGID INT, Kod VARCHAR(40), Nazwa VARCHAR(255), Poziom INT, GIDNumer INT, GrONumer INT, GIDTyp SMALLINT,GrOTyp SMALLINT, CzasModyfikacji INT PRIMARY KEY(Poziom, GrONumer, GIDNumer, GIDTyp))
AS
 BEGIN
  DECLARE @GIDTyp SMALLINT
  DECLARE @Poziom INT
  SET @GIDTyp = -16
   INSERT INTO @TwrGrupy (TwGID, Kod, Nazwa, Poziom, GIDNumer, GrONumer, GIDTyp, GrOTyp, CzasModyfikacji)
          SELECT TwG_TwGID, TwG_Kod, TwG_Nazwa, 0, TwG_GIDNumer, TwG_GrONumer, TwG_GIDTyp, TwG_GrOTyp, TwG_CzasModyfikacji
          FROM CDN.TwrGrupy
          WHERE TwG_GiDNumer = @GiDNumer and TwG_GIDTyp = -16
  SET @Poziom = 0
  WHILE 1=1
   BEGIN
    INSERT INTO @TwrGrupy (TwGID, Kod, Nazwa, Poziom, GIDNumer, GrONumer, GIDTyp, GrOTyp, CzasModyfikacji)
           SELECT TwG_TwGID, TwG_Kod, TwG_Nazwa,  @Poziom + 1, TwG_GIDNumer, TwG_GrONumer,TwG_GIDTyp, TwG_GrOTyp, TwG_CzasModyfikacji
           FROM @TwrGrupy JOIN CDN.TwrGrupy
           ON TwG_GrOTyp = @GIDTyp AND TwG_GrONumer = GIDNumer AND Poziom = @Poziom AND TwG_GIDTyp = -16 where  TwG_TwGID <> 0
    IF @@ROWCOUNT = 0 BREAK
    SET @Poziom = @Poziom + 1
   END
   INSERT INTO @TwrGrupy (TwGID, Kod, Nazwa, Poziom, GIDNumer, GrONumer, GIDTyp, GrOTyp, CzasModyfikacji)
          SELECT TwG_TwGID,  TwG_Kod, TwG_Nazwa,  1, TwG_GIDNumer, TwG_GrONumer, TwG_GIDTyp, TwG_GrOTyp, TwG_CzasModyfikacji
          FROM @TwrGrupy
          JOIN CDN.TwrGrupy ON TwG_GrOTyp = -16 AND TwG_GrONumer = GIDNumer  AND TwG_GIDTyp = 16
          WHERE  TwG_TwGID <> 0
 RETURN
END

Zapytanie SQL do funkcji:

-- {RootGroupId} ID grupy od której ma rozpocząć się pobieranie, w tym wypadku: 0, czyli wszystkie.
SELECT
     c.[Kod]
   , c.[Nazwa] AS Name
   , c.[Poziom]
   , c.[GIDNumer] AS id
   , REPLACE(c.[GrONumer] , {RootGroupId}, 0) AS ParentId
   , (SELECT p.[Kod] FROM CDN.fnTwrGrupy() AS p WHERE p.[GIDNumer] = c.[GrONumer]) AS [Parent] 
FROM CDN.TwrGrupy ({RootGroupId}) AS c WHERE GrONumer > 0 AND [GIDTyp] = -16

Czyli jak widać zwracana jest tabela, w której mam sztuczną relację, na zasadzie dodatkowej kolumny z ID rodzica.

To co potrzebuję zrobić, to zbudować drzewko TreeView tych grup.

Moja próba:

SqlCommand MsSqlCommand = DatabaseConnections.MsSqlConnection.CreateCommand();
DataSet Categories = new DataSet("Groups");
QueryBuilder _QueryBuilder = new QueryBuilder();
MsSqlCommand.CommandText = _QueryBuilder.GetGroups("0"); // _QueryBuilder.GetGroups("0") zwraca string zapytania do funkcji z parametrem 0.
SqlDataAdapter _SqlDataAdapter = new SqlDataAdapter(MsSqlCommand);

        _SqlDataAdapter.Fill(Categories, "Groups");
        Categories.Relations.Add("Relation",
            Categories.Tables["Groups"].Columns["ParentId"],
            Categories.Tables["Groups"].Columns["id"]);
        TreeNode nodeCategory, nodeSubCategory;
         //rowCategory;

        foreach (DataRow rowCategory in Categories.Tables["Groups"].Rows)
        {
            nodeCategory = new TreeNode();
            nodeCategory.Text = rowCategory["Name"].ToString();
            nodeCategory.Name = rowCategory["id"].ToString();
            this.treeView_Groups.Nodes.Add(nodeCategory);

            foreach (DataRow rowSubCategory in Categories.Tables["Groups"].Rows)
            {
                nodeSubCategory = new TreeNode();
                nodeSubCategory.Text = rowSubCategory["Name"].ToString();
                nodeSubCategory.Name = rowSubCategory["id"].ToString();
                this.treeView_Groups.Nodes.Add(nodeSubCategory);

            }
        }

<b>Niestety powyższy kod generuje błąd:</b>

> Parent Columns and Child Columns don't have type-matching columns.


UWAGA! Funkcji SQL nie mogę edytować, bo aktualizacja innego programu ją nadpisuje.
Normalnie pobrałbym schemat relacji z tabeli, ale to jest niestety funkcja. Niestety tabele zawierające grupy również nie posiadają zależności.

Z góry dziękuję za pomoc!
0

Kombinowałem, kombinowałem, aż się udało.
Rozwiązanie:

Najpierw zmieniłem zapytanie SQL do funkcji SQL:

-- {RootGroupId} oraz {ParentId} są zamieniane na ID rodzica.
SELECT
     c.[Kod]
   , c.[Nazwa] AS Name
   , c.[Poziom]
   , c.[GIDNumer] AS id
   , c.[GrONumer] AS ParentId
   , (SELECT p.[Kod] FROM CDN.fnTwrGrupy() AS p WHERE p.[GIDNumer] = c.[GrONumer]) AS [Parent] 
FROM CDN.TwrGrupyESklep ({RootGroupId}) AS c WHERE [GIDTyp] = -16
AND c.[GrONumer] = {ParentId}
ORDER BY c.[Kod]

Następnie pobierałem węzeł główny i wszystkie jego dzieci oraz dzieci dzieci.... Całość dzięki zastosowaniu funkcji rekurencyjnej:

private void PopulateGroups()
{

        SqlCommand MsSqlCommand = DatabaseConnections.MsSqlConnection.CreateCommand();
        DataSet Categories = new DataSet("Groups");
        QueryBuilder _QueryBuilder = new QueryBuilder();
        MsSqlCommand.CommandText = _QueryBuilder.GetGroups("0", "0"); //Funkcja zwraca Query String. Przykład powyżej.
        SqlDataAdapter _SqlDataAdapter = new SqlDataAdapter(MsSqlCommand);

        _SqlDataAdapter.Fill(Categories, "Groups");

        TreeNode nodeCategory;

        //Oczyść kontrolkę z istniejących wpisów:
        this.treeView_Groups.Nodes.Clear();

        foreach (DataRow rowCategory in Categories.Tables["Groups"].Rows)
        {
            nodeCategory = new TreeNode();
            nodeCategory.Text = (rowCategory["Name"].ToString() == "") ? rowCategory["Kod"].ToString() : rowCategory["Name"].ToString();
            nodeCategory.Name = rowCategory["id"].ToString();

            this.GetNodeChildren(nodeCategory, rowCategory["id"].ToString());

            this.treeView_Groups.Nodes.Add(nodeCategory);
        }

    }

    /// <summary>
    /// Rekurencyjna funkcja tworząca węzły grup i dodająca je do węzła głównego (rodzica głównego).
    /// </summary>
    /// <param name="ParentId">Identyfikator grupy rodzica, do którego należy dowiżac.</param>
    private void GetNodeChildren(TreeNode node, string ParentId)
    {
        SqlCommand MsSqlCommand = DatabaseConnections.MsSqlConnection.CreateCommand();
        DataSet Categories = new DataSet("GroupChildren");
        QueryBuilder _QueryBuilder = new QueryBuilder();
        MsSqlCommand.CommandText = _QueryBuilder.GetGroups(ParentId, ParentId);
        SqlDataAdapter _SqlDataAdapter = new SqlDataAdapter(MsSqlCommand);
        _SqlDataAdapter.Fill(Categories, "GroupChildren");
        TreeNode nodeSubCategory;

        foreach (DataRow rowSubCategory in Categories.Tables["GroupChildren"].Rows)
        {
            nodeSubCategory = new TreeNode();
            nodeSubCategory.Text = (rowSubCategory["Name"].ToString() == "") ? rowSubCategory["Kod"].ToString() : rowSubCategory["Name"].ToString();
            nodeSubCategory.Name = rowSubCategory["id"].ToString();
            node.Nodes.Add(nodeSubCategory);

            this.GetNodeChildren(nodeSubCategory, rowSubCategory["id"].ToString());
        }

    }

Może komuś się przyda...
Pozdrawiam!

1 użytkowników online, w tym zalogowanych: 0, gości: 1