如何使用C#MVC4将SQL Server数据列表转换为结构化JSON对象

如何使用C#MVC4将SQL Server数据列表转换为结构化JSON对象,c#,json,tsql,asp.net-mvc-4,C#,Json,Tsql,Asp.net Mvc 4,我正在开发一个MVC应用程序,它从SQLServer中的多个表中检索数据。该查询为我构建了一个结构化的分层JSON文件,我将该文件嵌入到我的d3.js树视图文件中。 这一切在原型级别对我来说都很好。现在,我需要在C#中动态构建JSON,并将其传递给视图以供使用。 我需要帮助构建C#逻辑以将数据转换为结构化JSON对象。 我已经阅读了这篇文章,但仍然需要帮助 这里是一个指向JSFIDLE.net的工作演示的链接——它包含嵌入的JSON,我的问题是从第229行开始 正如您所看到的,JSON可以有多达

我正在开发一个MVC应用程序,它从SQLServer中的多个表中检索数据。该查询为我构建了一个结构化的分层JSON文件,我将该文件嵌入到我的d3.js树视图文件中。 这一切在原型级别对我来说都很好。现在,我需要在C#中动态构建JSON,并将其传递给视图以供使用。
我需要帮助构建C#逻辑以将数据转换为结构化JSON对象。 我已经阅读了这篇文章,但仍然需要帮助

这里是一个指向JSFIDLE.net的工作演示的链接——它包含嵌入的JSON,我的问题是从第229行开始

正如您所看到的,JSON可以有多达10个级别的子级。我在这里使用的JSON是有史以来最大的JSON

下面是创建JSON的tsql

set nocount on

declare
  @sponsors table
  (num int,
   id int)

declare
  @customer_id int,
  @sponsor_id int,
  @sponsor_num int,
  @last_sponsor_id int,
  @last_customer_id int,
  @new_sponsor int,
  @tmp_num int,
  @tmp_id int,
  @json_text nvarchar(400);

declare data_cursor cursor for
with cte (customerid,
          thepath) as (
  SELECT customerid,
         convert(varbinary(max), customerid) as thepath
    FROM customers
    where customerid = 10013
    union all
    SELECT a.customerid,
         c.thepath + convert(varbinary(max), a.customerid) as thepath
    FROM customers a
         inner join cte c on
           a.sponsorid = c.customerid)
            select cus.customerid,
                   cus.sponsorid,
                   '{"ID": "' + convert(varchar(10),cus.customerid) + '",' +
            '"name": "' + 'cus.firstname ' + ' ' + 'cus.lastname' + '",' +
            '"fname": "' + cus.firstname + '",' +
            '"type": "' + case cus.customertypeid when 1 then 'C' else 'MP' end + '",' +
            '"phone": "' + '602-555-1212' + '",' +
            '"email": "' + 'dev@gmail.com' + '",' +
            '"paidranktxt": "' + isnull(pr.rankdescription,'') + '",' +
            '"ranktxt": "' + isnull(r.rankdescription,'') + '",' +
            '"PQV": "' + convert(varchar(10),isnull(pv.volume3,0)) + '",' +
            '"GQV": "' + convert(varchar(10),isnull(pv.volume5,0)) + '"' as json
            from cte
                  inner join customers cus
                 on cte.customerid = cus.customerid
                 and cus.customerstatusid <> 0
                   inner join periods per
                 on per.periodtypeid = 1
                 and per.periodid =
                 (select max(pv.periodid)
                    from periodvolumes pv
                   where pv.periodtypeid = 1)
               left join periodvolumes pv
                 on pv.customerid = cus.customerid
                 and per.periodid = pv.periodid
                 and per.periodtypeid = pv.periodtypeid
               left join ranks pr
                 on pv.paidrankid = pr.rankid
               left join ranks r
                 on pv.rankid = r.rankid
        order by cte.thepath;

    declare sponsor_cursor cursor for
      select num, id
        from @sponsors
       order by num desc;

    open data_cursor

    fetch next from  data_cursor
    into @customer_id,
         @sponsor_id,
         @json_text

    set @last_customer_id = 0;
    set @last_sponsor_id = 0;
    set @sponsor_num = 0;

    while @@fetch_status = 0
    begin
      set @new_sponsor = 0;

      if @last_customer_id = @sponsor_id
        begin
          print ', "children": ['
          set @sponsor_num = @sponsor_num + 1
    --print 'Insert: ' + convert(varchar(10),@sponsor_num) + ' ' + convert(varchar(10),@last_customer_id)
          insert into @sponsors (num, id)
            select @sponsor_num, @last_customer_id
        end
      else if @last_sponsor_id = @sponsor_id
        print '},'

      else if @last_customer_id > 0
        begin
          print '}'

          open sponsor_cursor

          fetch next from  sponsor_cursor
            into @tmp_num,
                 @tmp_id

          while @@fetch_status = 0
            begin
    --print 'Number: ' + convert(varchar(10),@tmp_num)
    --print 'ID: ' + convert(varchar(10),@tmp_id)

              if @sponsor_id = @tmp_id
                begin
                  print ','
                  set @new_sponsor = @tmp_num
                  break
                end
              else
                begin
                  set @sponsor_num = @sponsor_num - 1
                  print '] }'
                end

              fetch next from  sponsor_cursor
                into @tmp_num,
                     @tmp_id
            end
          close sponsor_cursor;
        end

      if @new_sponsor > 0
        delete from @sponsors where num > @new_sponsor

    --print 'Sponsor: ' + convert(varchar(10),@sponsor_id)
      print @json_text

      set @last_customer_id = @customer_id;
      set @last_sponsor_id = @sponsor_id;

      fetch next from data_cursor
      into @customer_id,
           @sponsor_id,
           @json_text
    end

    close data_cursor;

    deallocate data_cursor;

       begin
          print '}'

          open sponsor_cursor

          fetch next from  sponsor_cursor
            into @tmp_num,
                 @tmp_id

          if @@fetch_status <> 0
            print '] }'

          while @@fetch_status = 0
            begin
              if @sponsor_id = @tmp_id
                begin
                  print '] }'
                  set @new_sponsor = @tmp_num
                  break
                end
              else
                begin
                  set @sponsor_num = @sponsor_num - 1
                  print '] }'
                end

              fetch next from  sponsor_cursor
                into @tmp_num,
                     @tmp_id
            end
          close sponsor_cursor;
        end

如果我理解正确,您将停止使用t-sql代码生成JSON,而是希望使用C#将节点对象的层次结构转换为JSON

假设这是正确的,我的建议是简单地使用,如果您正在使用WebAPI(例如,您将在异步请求中使用javascript获取数据),那么这将非常简单,就像拥有一个具有如下操作的控制器一样:

[System.Web.Http.HttpGet]
public IEnumerable<Node> GetNodes() {
   IEnumerable<Node> nodes;
   ...
   // code to get Nodes from DB goes here
   ...

   return nodes;
}
最后,要将平面数据结构转换为层次结构,请执行以下操作:

class Program
{
    public class Node
    {
        public Node()
        {
            Children = new List<Node>();
        }

        public int ID { get; set; }
        public List<Node> Children { get; set; }
    }

    public class NhNode
    {
        public int ID { get; set; }
        public int SponsorId { get; set; }
    }

    static Node ConvertToHierarchy(NhNode nhnode, IEnumerable<NhNode> nodes)
    {
        var node = new Node()
        {
            ID = nhnode.ID
        };

        foreach (var item in nodes.Where(p => p.SponsorId == nhnode.ID))
        {
            node.Children.Add(ConvertToHierarchy(item, nodes));
        }

        return node;
    }

    static void Main(string[] args)
    {
        List<NhNode> nhnodes = new List<NhNode>() {
            new NhNode() { ID = 10013, SponsorId = 10000 },
            new NhNode() { ID = 10624, SponsorId = 10013 },
            new NhNode() { ID = 10975, SponsorId = 10624 }
        };

        var node = ConvertToHierarchy(nhnodes.First(p => p.SponsorId == 10000), nhnodes);
    }
}
类程序
{
公共类节点
{
公共节点()
{
Children=新列表();
}
公共int ID{get;set;}
公共列表子项{get;set;}
}
公共类NhNode
{
公共int ID{get;set;}
public int SponsorId{get;set;}
}
静态节点ConvertToHierarchy(NhNode NhNode,IEnumerable节点)
{
var节点=新节点()
{
ID=nhnode.ID
};
foreach(nodes.Where(p=>p.SponsorId==nhnode.ID)中的var项)
{
添加(ConvertToHierarchy(item,nodes));
}
返回节点;
}
静态void Main(字符串[]参数)
{
列表节点=新列表(){
新的NhNode(){ID=10013,SponsorId=10000},
新的NhNode(){ID=10624,SponsorId=10013},
新的NhNode(){ID=10975,SponsorId=10624}
};
var node=ConvertToHierarchy(nhnodes.First(p=>p.SponsorId==10000),nhnodes);
}
}

这有帮助吗?谢谢你的回复。我可能问错了,因为这是我第一次。我已经把TSQL关掉了。我的问题是在C#中执行相同的逻辑,并将其作为JSON对象传递给我的mvc视图。感谢您的回复。你对我需求的分析是正确的。在我的C#GetNodes中,当我像您一样操作时,建议返回的节点没有在所需的层次结构中格式化。看看js FIDLE文件,您将看到所需的格式。我需要一个c#类,它将执行与我的TSQL相同的逻辑。这篇文章解释了这一点,但我无法让它发挥作用。希望我的最新编辑涵盖了您需要的内容-将平面列表转换为层次结构列表-我简化了类以减少代码大小。这看起来会起作用。我会试试看。如果可以的话,我可能会有一些问题。这很有效,谢谢!不过我有一个简短的问题。当我改变这一点以获取SQL而不是硬编码值时,我遇到了一个问题,这一行var node=ConvertToHierarchy(nhnodes.First(p=>p.SponsorId==10000),nhnodes)…10000是什么?我应该在那里放置什么参数?这是层次结构的最顶层对象-如果您使用ID而不是sponsorid来标识该对象,您当然可以将其更改为类似var node=ConvertToHierarchy(nhnodes.First(p=>p.ID==10013),nhnodes)。
ID  sponsorid name  fname   type phone        email    paidranktxt ranktxt  PQV GQV
10013 10000   first Brian   MP   602-555-1234 d@m.com  TLeader      TL  0.00    13740.00
10624 10013   first Brian   MP   602-555-1234 d@m.com  TLeader      TL  0.00    13740.00
10975 10624   first Brian   MP   602-555-1234 d@m.com  TLeader      TL  0.00    13740.00
[System.Web.Http.HttpGet]
public IEnumerable<Node> GetNodes() {
   IEnumerable<Node> nodes;
   ...
   // code to get Nodes from DB goes here
   ...

   return nodes;
}
var config = GlobalConfiguration.Configuration;
var index = config.Formatters.IndexOf(config.Formatters.JsonFormatter);
config.Formatters[index] = new JsonMediaTypeFormatter
{
    SerializerSettings = new JsonSerializerSettings
    {
        //ContractResolver = new CamelCasePropertyNamesContractResolver(),
        DateTimeZoneHandling = DateTimeZoneHandling.Local
    }
};
class Program
{
    public class Node
    {
        public Node()
        {
            Children = new List<Node>();
        }

        public int ID { get; set; }
        public List<Node> Children { get; set; }
    }

    public class NhNode
    {
        public int ID { get; set; }
        public int SponsorId { get; set; }
    }

    static Node ConvertToHierarchy(NhNode nhnode, IEnumerable<NhNode> nodes)
    {
        var node = new Node()
        {
            ID = nhnode.ID
        };

        foreach (var item in nodes.Where(p => p.SponsorId == nhnode.ID))
        {
            node.Children.Add(ConvertToHierarchy(item, nodes));
        }

        return node;
    }

    static void Main(string[] args)
    {
        List<NhNode> nhnodes = new List<NhNode>() {
            new NhNode() { ID = 10013, SponsorId = 10000 },
            new NhNode() { ID = 10624, SponsorId = 10013 },
            new NhNode() { ID = 10975, SponsorId = 10624 }
        };

        var node = ConvertToHierarchy(nhnodes.First(p => p.SponsorId == 10000), nhnodes);
    }
}