PCB MS SQL 标量函数(CLR) 实现DataTable转Json方法

时间:2024-01-10 12:26:44

一.准备需转为json字符串的DataTable数据

在数据库中执行一段SQL返回的数据

PCB MS SQL 标量函数(CLR) 实现DataTable转Json方法

需转换后的JSON字符串的效果

[{"TechName":"开料","ItemName":"综合利用率是否为最高","ItemPara":"/"},{"TechName":"开料","ItemName":"综合利用率","ItemPara":"68.36"},{"TechName":"开料","ItemName":"纬向余料","ItemPara":"0"},{"TechName":"开料","ItemName":"经向余料","ItemPara":"0"},{"TechName":"开料","ItemName":"是否为小交货面积拼板","ItemPara":"n"},{"TechName":"开料","ItemName":"纬向尺寸","ItemPara":"24"},{"TechName":"开料","ItemName":"是否为阴阳铜结构","ItemPara":"N"},{"TechName":"开料","ItemName":"是否横竖开料","ItemPara":"N"},{"TechName":"开料","ItemName":"生产尺寸长","ItemPara":"24"},{"TechName":"开料","ItemName":"生产尺寸宽","ItemPara":"18"},{"TechName":"开料","ItemName":"拼板利用率","ItemPara":"68.36"},{"TechName":"开料","ItemName":"开料图纸","ItemPara":"/"},{"TechName":"开料","ItemName":"是否顾客指定板材","ItemPara":"N"},{"TechName":"开料","ItemName":"开料数","ItemPara":"4"},{"TechName":"开料","ItemName":"大料经向尺寸","ItemPara":"36"},{"TechName":"开料","ItemName":"大料纬向尺寸","ItemPara":"48"},{"TechName":"开料","ItemName":"成品尺寸长","ItemPara":"12"},{"TechName":"开料","ItemName":"成品尺寸宽","ItemPara":"13.5"},{"TechName":"开料","ItemName":"是否为PTFE板材","ItemPara":"N"},{"TechName":"开料","ItemName":"交货拼板个数","ItemPara":"1"},{"TechName":"开料","ItemName":"生产拼板个数","ItemPara":"1176"},{"TechName":"开料","ItemName":"交货单位","ItemPara":"U"},{"TechName":"开料","ItemName":"是否为凹蚀板材","ItemPara":"N"}]

二.C#写SQL SERVER(CLR)转JSON函数

先执行SQL返回DataTable,接着再将DataTable转为Json, 这里转为Json有2种方法,代码都贴在下方了

        /// <summary>
/// 执行SQL语句 返回的DataTable 转为 Json
/// </summary>
/// <param name="StrSQL"></param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)]
public static string ExecSQL2Json(string StrSQL)
{
DataTable dt = getDataTable(StrSQL);
//return DataTable2Json(dt); //方法1 转为 Json
if (dt is null)
return null;
List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
foreach (DataRow dr in dt.Rows)
{
Dictionary<string, object> result = new Dictionary<string, object>();
foreach (DataColumn dc in dt.Columns)
{
result.Add(dc.ColumnName, dr[dc].ToString());
}
list.Add(result);
}
return Json.Serialize(list);//方法2 转为 Json
}
/// <summary>
/// 执行SQL获取DataTable
/// </summary>
/// <param name="StrSQL"></param>
/// <returns></returns>
private static DataTable getDataTable(string StrSQL)
{
DataTable dt = new DataTable();
try
{
using (SqlConnection cn = new SqlConnection("context connection=true"))
{
using (SqlDataAdapter da = new SqlDataAdapter(StrSQL, cn))
{
DataSet ds = new DataSet();
da.Fill(ds, "tab");
dt = ds.Tables["tab"];
}
}
}
catch (Exception ex)
{
throw;
}
return dt;
}

方法一:DataTable转Json

        /// <summary>
/// DataTable转Json
/// </summary>
/// <param name="table"></param>
/// <returns></returns>
public static string DataTable2Json(DataTable table)
{
var JsonString = new StringBuilder();
if (table.Rows.Count > )
{
JsonString.Append("[");
for (int i = ; i < table.Rows.Count; i++)
{
JsonString.Append("{");
for (int j = ; j < table.Columns.Count; j++)
{
object ValueNull = table.Rows[i][j];
if (ValueNull == DBNull.Value)
{
JsonString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":null" + ((j < table.Columns.Count - ) ? "," : ""));
}
else
{
string Value = table.Rows[i][j].ToString();
if (table.Columns[j].DataType == typeof(string) || table.Columns[j].DataType == typeof(DateTime) || table.Columns[j].DataType == typeof(Guid))
{
JsonString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":" + "\"" + Value + "\"" + ((j < table.Columns.Count - ) ? "," : ""));
}
else
{
if (table.Columns[j].DataType == typeof(bool)) Value = Value.ToLower();
JsonString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":" + Value + ((j < table.Columns.Count - ) ? "," : ""));
}
} }
JsonString.Append("}" + ((i < table.Rows.Count - ) ? "," : ""));
}
JsonString.Append("]");
}
return JsonString.ToString();
}

方法二:  开源MiniJSON类解析Json字符串

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text; namespace SQLClr
{
/// <summary>
/// This class encodes and decodes JSON strings.
/// Spec. details, see http://www.json.org/
///
/// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
/// All numbers are parsed to doubles.
/// </summary>
public static class Json
{
/// <summary>
/// Parses the string json into a value
/// </summary>
/// <param name="json">A JSON string.</param>
/// <returns>An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false</returns>
//反序列化
public static object Deserialize(string json)
{
// save the string for debug information
if (json == null)
{
return null;
} return Parser.Parse(json);
}
//阻止其他类从该类继承
sealed class Parser : IDisposable
{
const string WORD_BREAK = "{}[],:\""; public static bool IsWordBreak(char c)
{
// 如果 c 是空白,则为 true;否则,为 false;报告指定 Unicode 字符在此字符串中的第一个匹配项的索引。
return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -;
} enum TOKEN
{
NONE,
CURLY_OPEN,
CURLY_CLOSE,
SQUARED_OPEN,
SQUARED_CLOSE,
COLON,
COMMA,
STRING,
NUMBER,
TRUE,
FALSE,
NULL
};
// 实现从字符串进行读取的 System.IO.TextReader。
StringReader json; Parser(string jsonString)
{
json = new StringReader(jsonString);
} public static object Parse(string jsonString)
{
using (var instance = new Parser(jsonString))
{
return instance.ParseValue();
}
}
//释放
public void Dispose()
{
json.Dispose();
json = null;
} Dictionary<string, object> ParseObject()
{
Dictionary<string, object> table = new Dictionary<string, object>(); // ditch opening brace
json.Read(); // {
while (true)
{
switch (NextToken)
{
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.CURLY_CLOSE:
return table;
default:
// name
string name = ParseString();
if (name == null)
{
return null;
} // :
if (NextToken != TOKEN.COLON)
{
return null;
}
// ditch the colon
json.Read(); // value
table[name] = ParseValue();
break;
}
}
} List<object> ParseArray()
{
List<object> array = new List<object>(); // ditch opening bracket
json.Read(); // [
bool parsing = true;
while (parsing)
{
TOKEN nextToken = NextToken; switch (nextToken)
{
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.SQUARED_CLOSE:
parsing = false;
break;
default:
object value = ParseByToken(nextToken); array.Add(value);
break;
}
} return array;
} object ParseValue()
{
TOKEN nextToken = NextToken;
return ParseByToken(nextToken);
} object ParseByToken(TOKEN token)
{
switch (token)
{
case TOKEN.STRING:
return ParseString();
case TOKEN.NUMBER:
return ParseNumber();
case TOKEN.CURLY_OPEN:
return ParseObject();
case TOKEN.SQUARED_OPEN:
return ParseArray();
case TOKEN.TRUE:
return true;
case TOKEN.FALSE:
return false;
case TOKEN.NULL:
return null;
default:
return null;
}
} string ParseString()
{
StringBuilder s = new StringBuilder();
char c; // ditch opening quote
json.Read(); bool parsing = true;
while (parsing)
{ if (json.Peek() == -)
{
parsing = false;
break;
} c = NextChar;
switch (c)
{
case '"':
parsing = false;
break;
case '\\':
if (json.Peek() == -)
{
parsing = false;
break;
} c = NextChar;
switch (c)
{
case '"':
case '\\':
case '/':
s.Append(c);
break;
case 'b':
s.Append('\b');
break;
case 'f':
s.Append('\f');
break;
case 'n':
s.Append('\n');
break;
case 'r':
s.Append('\r');
break;
case 't':
s.Append('\t');
break;
case 'u':
var hex = new char[]; for (int i = ; i < ; i++)
{
hex[i] = NextChar;
} s.Append((char)Convert.ToInt32(new string(hex), ));
break;
}
break;
default:
s.Append(c);
break;
}
} return s.ToString();
} object ParseNumber()
{
string number = NextWord;
// 摘要:
// 报告指定 Unicode 字符在此字符串中的第一个匹配项的索引。
//
// 参数:
// value:
// 要查找的 Unicode 字符。
//
// 返回结果:
// 如果找到该字符,则为 value 的从零开始的索引位置;如果未找到,则为 -1。
if (number.IndexOf('.') == -)
{
long parsedInt;
// 将数字的字符串表示形式转换为它的等效 64 位有符号整数。一个指示转换是否成功的返回值。
Int64.TryParse(number, out parsedInt);
return parsedInt;
} double parsedDouble;
Double.TryParse(number, out parsedDouble);
return parsedDouble;
}
//
void EatWhitespace()
{
//指示指定字符串中位于指定位置处的字符是否属于空白类别。
while (Char.IsWhiteSpace(PeekChar))
{
json.Read();
//摘要:
// 返回下一个可用的字符,但不使用它。
//
// 返回结果:
// 表示下一个要读取的字符的整数,或者,如果没有更多的可用字符或该流不支持查找,则为 -1。
if (json.Peek() == -)
{
break;
}
}
} char PeekChar
{
get
{
// 读取输入字符串中的下一个字符并将该字符的位置提升一个字符。
//
// 返回结果:
// 基础字符串中的下一个字符,或者如果没有更多的可用字符,则为 -1。
return Convert.ToChar(json.Peek());
}
} char NextChar
{
get
{
return Convert.ToChar(json.Read());
}
} string NextWord
{
get
{
// 表示可变字符字符串。无法继承此类。
StringBuilder word = new StringBuilder(); while (!IsWordBreak(PeekChar))
{
// 摘要:
// 在此实例的结尾追加指定 Unicode 字符的字符串表示形式。
//
// 参数:
// value:
// 要追加的 Unicode 字符。
//
// 返回结果:
// 完成追加操作后对此实例的引用。
word.Append(NextChar);
//下一个字符为空
if (json.Peek() == -)
{
break;
}
}
//
return word.ToString();
}
} TOKEN NextToken
{
get
{
EatWhitespace(); if (json.Peek() == -)
{
return TOKEN.NONE;
} switch (PeekChar)
{
case '{':
return TOKEN.CURLY_OPEN;
case '}':
json.Read();
return TOKEN.CURLY_CLOSE;
case '[':
return TOKEN.SQUARED_OPEN;
case ']':
json.Read();
return TOKEN.SQUARED_CLOSE;
case ',':
json.Read();
return TOKEN.COMMA;
case '"':
return TOKEN.STRING;
case ':':
return TOKEN.COLON;
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '-':
return TOKEN.NUMBER;
} switch (NextWord)
{
case "false":
return TOKEN.FALSE;
case "true":
return TOKEN.TRUE;
case "null":
return TOKEN.NULL;
} return TOKEN.NONE;
}
}
} /// <summary>
/// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
/// </summary>
/// <param name="json">A Dictionary<string, object> / List<object></param>
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
public static string Serialize(object obj)
{
return Serializer.Serialize(obj);
} sealed class Serializer
{
StringBuilder builder; Serializer()
{
//创建生成器
builder = new StringBuilder();
}
//序列化
public static string Serialize(object obj)
{
var instance = new Serializer(); instance.SerializeValue(obj); return instance.builder.ToString();
}
//类型
void SerializeValue(object value)
{
IList asList;
IDictionary asDict;
string asStr; if (value == null)
{
builder.Append("null");
}
else if ((asStr = value as string) != null)
{
SerializeString(asStr);
}
else if (value is bool)
{
builder.Append((bool)value ? "true" : "false");
}
else if ((asList = value as IList) != null)
{
SerializeArray(asList);
}
else if ((asDict = value as IDictionary) != null)
{
SerializeObject(asDict);
}
else if (value is char)
{
SerializeString(new string((char)value, ));
}
else
{
SerializeOther(value);
}
}
//序列化对象
void SerializeObject(IDictionary obj)
{
bool first = true; builder.Append('{'); foreach (object e in obj.Keys)
{
if (!first)
{
builder.Append(',');
} SerializeString(e.ToString());
builder.Append(':'); SerializeValue(obj[e]); first = false;
} builder.Append('}');
}
// 序列化数组
void SerializeArray(IList anArray)
{
builder.Append('['); bool first = true; foreach (object obj in anArray)
{
if (!first)
{
builder.Append(',');
} SerializeValue(obj); first = false;
} builder.Append(']');
}
//string
void SerializeString(string str)
{
builder.Append('\"'); char[] charArray = str.ToCharArray();
foreach (var c in charArray)
{
switch (c)
{
case '"':
builder.Append("\\\"");
break;
case '\\':
builder.Append("\\\\");
break;
case '\b':
builder.Append("\\b");
break;
case '\f':
builder.Append("\\f");
break;
case '\n':
builder.Append("\\n");
break;
case '\r':
builder.Append("\\r");
break;
case '\t':
builder.Append("\\t");
break;
default:
int codepoint = Convert.ToInt32(c);
if ((codepoint >= ) && (codepoint <= ))
{
builder.Append(c);
}
else
{
//builder.Append("\\u");
//builder.Append(codepoint.ToString("x4"));
builder.Append(c);
}
break;
}
} builder.Append('\"');
}
//其他
void SerializeOther(object value)
{
// NOTE: decimals lose precision during serialization.
// They always have, I'm just letting you know.
// Previously floats and doubles lost precision too.
//注意:小数在序列化过程中丢失精度。
//他们总是有,我只是让你知道。
//以前失去精度和双精度浮点数。
if (value is float)
{
builder.Append(((float)value).ToString("R"));
}
else if (value is int
|| value is uint
|| value is long
|| value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is ulong)
{
builder.Append(value);
}
else if (value is double
|| value is decimal)
{
builder.Append(Convert.ToDouble(value).ToString("R"));
}
else
{
SerializeString(value.ToString());
}
}
}
}
}

三.SQL服务器CLR配置(允许SQL调用.net程序)

    sp_configure 'show advanced options', 1;
RECONFIGURE WITH override
GO
sp_configure 'clr enabled', 1;
RECONFIGURE WITH override
GO
Sp_changedbowner 'sa',true --sa改为当前登入用户名
alter database [dbname] set trustworthy on --bbname 改为自己的库名

四.注册 CLR 程序集

   create  ASSEMBLY SQLfunctionAssembly
FROM 'D:\SQLClr.dll' --改为自己C#写的dll路径填写
WITH PERMISSION_SET = UNSAFE;

创建的.net程序集数据会写入下表:

  select * from sys.assemblies
select * from sys.assembly_files

PCB MS SQL 标量函数(CLR) 实现DataTable转Json方法

五.创建标量函数

create  FUNCTION [dbo].[ExecSQL2Json](@StrSQL [nvarchar](max))
RETURNS [nvarchar](max) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [SQLfunctionAssembly].[SQLClr.SQLfunction].[ExecSQL2Json]

六.测试DataTable转Json函数

DECLARE @SQL VARCHAR(MAX)
SET @SQL = 'SELECT TechName,ItemName,ItemPara
FROM FP_EMS_DB.dbo.V_ppegeneral
WHERE pdctno = ''2V011Z30A4'' AND TechNo = ''CC_01'' ORDER BY ItemNo '
SELECT dbo.ExecSQL2Json(@SQL)

运行后结果

PCB MS SQL 标量函数(CLR) 实现DataTable转Json方法

七.小结

采用CLR方式写SQL SERVER函数转为json字符串,那么只要传入一段SQL语句就可以转为Json字符串,是不是很方便,但这种作法在实际应用中作用不太大,因为业务系统现在基本采用ORM 对象关系映射模型开发,数据库表映射成对象,直接操作的对象,然而对象转为json放在应用程序端转换是及为方便的,在这里只开拓一种新思路在数据库中实现转json的方法。