Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Иерархические данные. В поиске оптимального решения

Anna | 18.06.2014 | нет комментариев
Исследуя обширные пространства интернета мне пришлось потрудиться над тем как же все таки сделать не массивный код на asp.net c# для обработки так называемых «свинных ушей», которые содержат классическую модель родитель-потомок в базе данных. Сразу оговорюсь база в SQL Server 2008, тот, что теснее имеет вероятность работы с иерархическими данными в ОТВ(CTE — английский вариант сокращения).

В моей системе строится модель бизнес-процессов, которая должна удовлетворять эталону SADT и таблица выглядит как приведено ниже на рисунке 1.
Рисунок 1. Модель

Тут BPNumber — число которое характеризует порядок бизнес-процесса на своем ярусе иерархии. К примеру вначале идет подсистема УУ(«Учебное управление») -1, «Кафедра» — 2, а после этого «Деканат» — 3(рис. 2).

К примеру, итог должен выглядеть примерно так:

Рисунок 2. Итог

Разглядев примеры реализации, описанные другими авторами, а так же справки с msdn автор пришла к итогу, что вытягивать все одним списком в ОТВ и обрабатывать потом средствами asp.net лишняя загрузка сервера на построение запроса с рекурсией, да и обойти ее выстроив xml для загрузки в дерево все равно нужно будет писать бесчисленный код. Не оптимально подумала я.
Решив, что средствами t-sql не коротко, продолжила поиск теснее в других направлениях. И обнаружила вот эту статью работа с иерархическими данными в asp.net mvc. Может подлинно кому-то поможет?

А вот решение обнаруженное тут Display Hierarchical Data with TreeView in ASP.NET 2.0 поразило простотой и взяв его за основу я решила поставленную выше задачу для отображения такого как нужно списка. Для реформирования значения NULL в -1 следует изменить запрос дальнейшим образом:

SqlCommand dbCommand = new SqlCommand("SELECT  [BusinessProcessID], [BPName], [ProjectID], case when [BusinessProcessIDTOP] IS NULL  then -1 else [BusinessProcessIDTOP] end as [BusinessProcessIDTOP] FROM [BusinessProcess] WHERE ([ProjectID] = "   HiddenField1.Value.ToString()   ") order by BPNumber", myConn);

Листинг 1. Поиск верхнего узла
Ну а каждый листинг выглядит вот таким образом

using System.Data.SqlClient;

public partial class bptree : System.Web.UI.Page
{
    DataTable dtTree = new DataTable();
    protected void Page_Load(object sender, EventArgs e)
    {

        String strConnect = SqlDataSource1.ConnectionString;
        SqlConnection myConn = new SqlConnection(strConnect);
        myConn.Open();
        SqlCommand dbCommand = new SqlCommand("SELECT  [BusinessProcessID], [BPName], [ProjectID], case when [BusinessProcessIDTOP] IS NULL  then -1 else [BusinessProcessIDTOP] end as [BusinessProcessIDTOP] FROM [BusinessProcess] WHERE ([ProjectID] = "   HiddenField1.Value.ToString()   ") order by BPNumber", myConn);
        SqlDataAdapter da = new SqlDataAdapter(dbCommand);
        da.Fill(dtTree);
        da.Dispose();
        dbCommand.Dispose();
        myConn.Dispose();
        if (!IsPostBack)
        AddNodes(-1, TreeView1.Nodes);

    }
    void AddNodes(int id, TreeNodeCollection tn)
    {
        foreach (DataRow dr in dtTree.Select("BusinessProcessIDTOP = "   id))
        {
            TreeNode sub = new TreeNode(dr["BPName"].ToString(), dr["BusinessProcessID"].ToString());
            tn.Add(sub);
            AddNodes(Convert.ToInt32(sub.Value), sub.ChildNodes);
        }
    }

}

Листинг 2. Решение задачи в 2 способах

Ну а что же касается ОТВ. То для описанных ниже задач думаю они подходят отменнее:

  • Поиск заданного яруса узла
  • Вычисления пути(к примеру с файлами)
  • Нахождения узлов, имеющих нужных прародителей
  • Ну и массовые вычисления, которые определены во множестве

К примеру приведу код t-sql с ОТВ:

/****** Сценарий для ОТВ  ******/
with cte_bp([BusinessProcessID]
      ,[BPName],[BusinessProcessIDTOP], level ,paths)
      as
(SELECT  [BusinessProcessID]
      ,[BPName]
      ,[BusinessProcessIDTOP], 0 as level, CAST([BPName]as nvarchar(max)) '/'

  FROM [cmk].[dbo].[BusinessProcess]
  where [ProjectID]=1 and BusinessProcessIDTOP is null

UNION ALL
SELECT  [BusinessProcess].[BusinessProcessID]
      ,[BusinessProcess].[BPName]
      ,[BusinessProcess].[BusinessProcessIDTOP], level 1, d.paths  cast([BusinessProcess].[BPName] as nvarchar(max)) '/'

  FROM [cmk].[dbo].[BusinessProcess]
  Inner join cte_bp as d on d.BusinessProcessID=BusinessProcess.BusinessProcessIDTOP
 )
-- Statement using the CTE
SELECT *, SPACE(level) BPName as ch
FROM cte_bp order by paths,BusinessProcessID

Листинг 3. Работа с ОТВ

Вот возвращенный итог:


Рисунок 3. Итог запроса

Думаю приведенный пример поможет тем, кто как и автор этого топика ищет банальное и стремительное решение для отображения иерархических данных, хранящихся на SQL Server 2008 и выше.

Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB