sql server2016中的Camel Case JsonObject数组

时间:2017-03-02 17:36:29

标签: json.net sql-server-2016

我使用"来自SqlServer 2016返回Json;对于JSON AUTO"我的操作就像这样

"[{\"Id\":3,\"SId\":\"5801\",\"Name\":\"Pizza\",\"Type\":\"Error\"}]"

我使用以下代码反序列化数据

 public Someclass GetData(int Id)
    {
        using (var dataContext = new DataContext(_connectionString))
        {
               var serializer = new JsonSerializerSettings()
               {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
               };
            var dataArray = dataContext.ExecuteQuery<string>(query.ToString()).SingleOrDefault();
            dynamic obj= JsonConvert.DeserializeObject<dynamic>(dataArray , serializer);

            return obj
        }
    }

在obj对象中,我没有获得camelcased数据。它的格式低于

 "{[{"Id":3,SId":"5801","Name":"Pizza","Type":"Error"}]}" 

由于我的数据结构保持json结果是动态的,我无法使用json.net将其转换为camelcase。是否有任何sql方法从sql server 2016返回camelcase列名称

2 个答案:

答案 0 :(得分:2)

我编写了一个存储过程来将任意JSON转换为camelcase。它涵盖了我能想到的大多数数据类型,但可能会有一些JSON会破坏它。我很想让它成为一个函数,但你不能在函数中做动态的SQL。

CREATE PROCEDURE [dbo].[CamelCaseJson] (
    @jsonIn nvarchar(max),
    @jsonOut nvarchar(max) output
)
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @isArray    BIT = 0
    DECLARE @innerCols  NVARCHAR(MAX)
    DECLARE @outerCols  NVARCHAR(MAX)
    DECLARE @sql        NVARCHAR(MAX)

    IF LEFT(@jsonIn, 1) = '['
    BEGIN
        SET @isArray = 1
    END

    CREATE TABLE #tmpData (
        [rownum]            INT IDENTITY(1, 1),
        [key]               NVARCHAR(MAX),
        [value]             NVARCHAR(MAX),
        [type]              INT,
        [processedKey]      NVARCHAR(MAX),
        [processedValue]    NVARCHAR(MAX)
    )

    DECLARE @jsons TABLE (
        [rownum]    INT,
        [json]      NVARCHAR(MAX)
    )

    INSERT #tmpData (
        [key],
        [value],
        [type],
        [processedKey],
        [processedValue]
    )
    SELECT
        [key],
        [value],
        [type],
        LOWER(SUBSTRING([key], 1, 1)) + SUBSTRING([key], 2, 999999999),
        [value]
    FROM OPENJSON(@jsonIn)  


    INSERT @jsons (
        [rownum],
        [json]
    )
    SELECT
        [rownum],
        [value]
    FROM #tmpData
    WHERE [type] in (4, 5)


    DECLARE @id         INT
    DECLARE @subJsonIn  NVARCHAR(MAX)
    DECLARE @subJsonOut NVARCHAR(MAX)

    WHILE EXISTS (SELECT 1 FROM @jsons)
    BEGIN
        SET @subJsonOut = NULL

        SELECT 
            TOP 1 
            @id = [rownum],
            @subJsonIn = [json]
        FROM @jsons

        EXEC [dbo].[CamelCaseJson] @subJsonIn, @subJsonOut OUTPUT

        UPDATE #tmpData
        SET [processedValue] = @subJsonOut
        WHERE [rownum] = @id

        DELETE @jsons WHERE [rownum] = @id
    end


    IF @isArray = 0
    BEGIN
        SELECT @innerCols = COALESCE(@innerCols + ', ', '') + QUOTENAME([processedKey]) FROM #tmpData

        SELECT @outerCols = 
            COALESCE(@outerCols + ', ', '') 
                +   CASE    
                        WHEN [type] = 2 AND [value] LIKE '%e%' THEN 'CAST(' + QUOTENAME([processedKey]) + ' AS FLOAT) AS ' + QUOTENAME([processedKey])
                        WHEN [type] = 2 AND [value] LIKE '%.%' THEN 'CAST(' + QUOTENAME([processedKey]) + ' AS DECIMAL(19, 7)) AS ' + QUOTENAME([processedKey])
                        WHEN [type] = 2 THEN 'CAST(' + QUOTENAME([processedKey]) + ' AS INT) AS ' + QUOTENAME([processedKey])
                        WHEN [type] = 3 THEN 'CAST(' + QUOTENAME([processedKey]) + ' AS BIT) AS ' + QUOTENAME([processedKey])
                        WHEN [type] in (4, 5) THEN 'JSON_QUERY(' + QUOTENAME([processedKey]) + ') AS ' + QUOTENAME([processedKey])
                        ELSE QUOTENAME([processedKey]) 
                    END
        FROM #tmpData 


        SET @sql = '
            WITH pv AS (
                SELECT
                    [dummy] = 1,
                    [key] = [processedKey],
                    [value] = [processedValue]
                FROM #tmpData
            )
            SELECT @dynout = (
                SELECT ' + @outerCols + '
                FROM (
                    SELECT [dummy], ' + @innerCols + '
                    FROM pv
                    PIVOT (
                        MAX([value]) FOR [key] IN (' + @innerCols + ')
                    ) pvresult
                ) x
                FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES
            )
        '

        EXEC sp_executesql @sql, N'@dynout NVARCHAR(MAX) OUT', @jsonOut OUTPUT
    END
    ELSE
    BEGIN
        SELECT @jsonOut = 
            COALESCE(@jsonOut + ',', '') + 
                CASE
                    WHEN [type] = 1 THEN '"' + [processedValue] + '"' 
                    ELSE [processedValue]
                END
        FROM #tmpData 
        ORDER BY [rownum]

        SET @jsonOut = '[' + @jsonOut + ']'
    END

    DROP TABLE #tmpData
END
GO

检查你的例子:

DECLARE @jsonIn     NVARCHAR(MAX)
DECLARE @jsonOut    NVARCHAR(MAX)


SET @jsonIn = (
    SELECT
        [Id] = 3,
        [SId] = '5801',
        [Name] = 'Pizza',
        [Type] = 'Error'
    FOR JSON PATH
)

EXEC [dbo].[CamelCaseJson] @jsonIn, @jsonOut OUTPUT

SELECT @jsonIn [Json]
UNION ALL
SELECT @jsonOut [Json]

给你

  

在[{“Id”:3,“SId”:“5801”,“名称”:“披萨”,“类型”:“错误”}]

     

Out [{“id”:3,“sId”:“5801”,“name”:“Pizza”,“type”:“Error”}]

我的单元测试JSON(格式不对,抱歉):

{"Pnull":null,"Pstring":"Foo","Pint":1,"Pdec":1.3,"Pbool":true,"Pstrarray":["a","b"],"Pintarray":[1,3,5],"Parray":[{"Prop":"val1"},{"Prop":"val2"}],"Pjson":{"Subproperty":1},"Pjsonstring":"{\"Subproperty\":2}","Poffset":"2017-06-20T22:18:31.2279221-04:00","DeepObj":{"Level":2,"Sub":{"Level":3,"Sub":{"Level":4,"Sub":{"Level":"Basement"}}}},"Flt":1.3e-9}

答案 1 :(得分:0)

他们希望这个json输出来自“select ... for json auto”:

[{ “ID”:3 “SID”: “5801”, “名称”: “比萨饼”, “类型”: “错误”}]

如果您在javascript中直接使用SQL输出,您可能会担心它不是驼峰式的。但是,在上面的代码中,SQL正在.NET程序中使用,而.NET反序列化不区分大小写。无需使用动态类型或混乱串行器设置。只需直接反序列化为SomeClass

var someClass = JSONConvert.DeserializeObject<SomeClass>(dataArray)

但请注意,您应该在C#代码中使用C#约定 - 所以SomeClass应该使用Pascal案例名称。如果你要从.NET WebApi返回SomeClass,那么当你应该转换为驼峰的时候 。在.NET Core中,这是默认完成的。对于.NET Framework,您可以在应用程序初始化时更改JSON序列化程序设置以执行相同的操作。

但如果你真的想要:

[{"id":3,"sId":"5801","name":"pizza","type":"Error"}]

如果可以的话,

修改查询本身并在任何情况下明确列出列:

select id, sId, name, type from ... for json auto