【问题标题】:How to convert SQL Server data list into a structured JSON object with C# MVC4如何使用 C# MVC4 将 SQL Server 数据列表转换为结构化 JSON 对象
【发布时间】:2014-02-11 21:38:13
【问题描述】:

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

这是一个工作演示 http://jsfiddle.net/hoopkjaz/d5Azm/ 的 JSfiddle.net 的链接 - 它包含我的问题是关于从第 229 行开始的嵌入式 JSON。

如您所见,JSON 最多可以有 10 个子级。我在这里使用的 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

这是应该保存列表的类

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

    public int ID { get; set; }
    public string Name { get; set; }
    public string Fname { get; set; }
    public string Type { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
    public string Paidranktxt { get; set; }
    public string Ranktxt { get; set; }
    public string PQV { get; set; }
    public string GQV { get; set; }
    public List<Node> Children { get; set; }
}   

这是我从 SQL 中提取列表的方法

 public static IEnumerable<Node> GetNode(int? customerId)
    {
        try
        {

            const string query = @"  SQL from above goes here";                           

            var jsonResult = TransactionManager.Current.Entities.Database.SqlQuery<Node>(query,new SqlParameter("CustomerID", customerId));                                                                          
            return jsonResult;
        }
        catch (Exception e)
        {
            // log the error in Elmah
            e.LogToElmah();
            return null;
        }

这是格式化前的 SQL 示例。我们使用赞助商来确定孩子

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

【问题讨论】:

  • 感谢您的回复。我可能问错了,因为这是我第一次。我实际上已经关闭了 TSQL。我的问题是在 C# 中执行相同的逻辑并将其作为 JSON 对象传递给我的 mvc 视图。

标签: c# json tsql asp.net-mvc-4


【解决方案1】:

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

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

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

   return nodes;
}

要配置 JSON.Net 以在 WebAPI 中使用,您的 Global.asax 中的类似内容将起作用:

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);
    }
}

【讨论】:

  • rfernandes 感谢您的回复。您对我的需求的分析是正确的。在我的 C# GetNodes 中,当我这样做时,建议返回的节点未按所需的层次结构进行格式化。查看 js fiddle 文件,您将看到所需的格式。我需要一个 c# 类来执行与我的 TSQL 相同的逻辑。这篇文章解释了它,但我无法让它工作。 stackoverflow.com/questions/6945216/…
  • 希望我的最新编辑涵盖了您所需要的 - 将平面列表转换为分层列表 - 我已经简化了类以减少代码大小。
  • 这看起来可行。我会试试看。如果可以的话,我可能会在此过程中遇到一些问题。
  • 这很好用,谢谢!不过,我确实有一个快速的问题。当我更改它以获取 SQL 而不是硬编码值时,我遇到了这一行的一个问题 var node = ConvertToHierarchy(nhnodes.First(p => p.SponsorId == 10000), nhnodes)... 10000 可以吗?我在那里放置什么参数?
  • 这是层次结构的最顶层对象 - 如果您使用 ID 而不是赞助商标识来标识该对象,您当然可以将其更改为类似 var node = ConvertToHierarchy(nhnodes.First(p => p.ID == 10013),nhnodes)。
猜你喜欢
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-19
  • 2012-12-15
  • 2016-06-04
  • 1970-01-01
相关资源
最近更新 更多