有没有办法为 JSON 列强制执行特定的 JSON 结构?

问题描述 投票:0回答:1

我的表中有一个列将保存 JSON 对象。我目前将列定义为

MY_JSON_COLUMN NVARCHAR(MAX)

有没有办法确保 JSON 遵循特定的结构?

例如,在存储 JSON 之前,检查 JSON 是否具有这种特定结构

"
{
  name: '',
  description: '',
  friends: [
   {
     name: ''
     description: '',
   }
  ]
}
"

如果可能,我如何确保 JSON 的结构与上面的结构完全相同,并且包含所有键?

这在数据库端是不可能的,但在保存之前应该在客户端或后端检查吗?

我的想法是拥有一个像上面这样的主 JSON 模板,并将其用作一种测试检查器来与尝试存储的请求 JSON 进行比较

c# sql .net sql-server
1个回答
0
投票

您应该在应用程序和数据库中检查这一点。

在应用程序中,您应该使用对象模型来强制执行此操作。例如:

public class Node
{
    public string Name { get; set; }
    public string Description { get; set; }
    public List<Node> Friends { get; set; }
}

在 SQL Server 中,您可以使用

CHECK
约束,但无法检查数组。

ALTER TABLE YourTable
ADD CONSTRAINT JsonMatching CHECK (
    ISJSON(MY_JSON_COLUMN) = 1 AND
    JSON_VALUE(MY_JSON_COLUMN, '$.name') IS NOT NULL AND
    JSON_VALUE(MY_JSON_COLUMN, '$.description') IS NOT NULL AND
    JSON_QUERY(MY_JSON_COLUMN, '$.friends') IS NOT NULL
);

递归检查数组的唯一方法是使用用户定义的函数

CREATE OR ALTER FUNCTION dbo.IsJsonMatching (@json nvarchar(max))
RETURNS BIT
WITH RETURNS NULL ON NULL INPUT
AS BEGIN
    RETURN
      CASE WHEN EXISTS (SELECT 1
        FROM OPENJSON(@json)
          WITH (
           name nvarchar(4000),
           description nvarchar(4000),
           friends nvarchar(max) AS JSON
          ) j
        WHERE j.name IS NULL
           OR j.description IS NULL
           OR j.friends IS NOT NULL AND dbo.IsJsonMatching(j.friends) = 1
      ) THEN CAST(0 AS bit) ELSE CAST(1 AS bit) END;
END;
ALTER TABLE YourTable
ADD CONSTRAINT JsonMatching CHECK (
    ISJSON(MY_JSON_COLUMN) = 1 AND dbo.IsJsonMatching(MY_JSON_COLUMN) = 1
);

但是,我强烈建议您不要走这条路。如果您的模式是严格定义的,那么您应该使用正确的表,而不是松散定义的 JSON。

例如,分层表可能如下所示:

CREATE TABLE Node (
    Id bigint NOT NULL PRIMARY KEY,
    Name nvarchar(100) NOT NULL,
    Description nvarchar(1000) NOT NULL
);

CREATE TABLE NodeFriend (
    Id bigint REFERENCES Node (Id),
    FriendId bigint REFERENCES Node (Id),
    PRIMARY KEY (Id, FriendId),
    INDEX IX_2 (FriendId, Id),
    CHECK (Id < FriendId)
);
© www.soinside.com 2019 - 2024. All rights reserved.