我的表中有一个列将保存 JSON 对象。我目前将列定义为
MY_JSON_COLUMN NVARCHAR(MAX)
有没有办法确保 JSON 遵循特定的结构?
例如,在存储 JSON 之前,检查 JSON 是否具有这种特定结构
"
{
name: '',
description: '',
friends: [
{
name: ''
description: '',
}
]
}
"
如果可能,我如何确保 JSON 的结构与上面的结构完全相同,并且包含所有键?
这在数据库端是不可能的,但在保存之前应该在客户端或后端检查吗?
我的想法是拥有一个像上面这样的主 JSON 模板,并将其用作一种测试检查器来与尝试存储的请求 JSON 进行比较
您应该在应用程序和数据库中检查这一点。
在应用程序中,您应该使用对象模型来强制执行此操作。例如:
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)
);