如何使用C#MVC4将SQL Server数据列表转换为结构化JSON对象
我正在开发一个MVC应用程序,它从SQLServer中的多个表中检索数据。该查询为我构建了一个结构化的分层JSON文件,我将该文件嵌入到我的d3.js树视图文件中。 这一切在原型级别对我来说都很好。现在,我需要在C#中动态构建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可以有多达
我需要帮助构建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);
}
}