Невозможно вставить в две таблицы при использовании RLS
Прежде всего, позвольте мне предисловие, сказав, что я новичок в развивающихся странах. Я начинал как стажер около месяца назад, поэтому есть большая вероятность, что я не смогу правильно объяснить себя. За это я прошу прощения.
Теперь вот проблема: я пишу набор конечных точек для API, используя C# и Entity Framework Core. В принципе, фильтрация должна быть установлена на уровне базы данных, поэтому мы используем RLS для этого. Для этого я написал следующий предикат и политику:
USE [DBO]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [sec].[RestrictApplicationsByUser](@ApplicationId int)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS RestrictApplicationsByUserResult
WHERE
@ApplicationId IN (SELECT
ApplicationId
FROM
[usr].[UserApplications]
WHERE
UserId = CAST(SESSION_CONTEXT(N'UserId') AS uniqueidentifier))
OR SESSION_CONTEXT(N'UserId') IS NULL;
GO
А также
USE [DBO]
GO
CREATE SECURITY POLICY [sec].[FilterApplicationByUser]
ADD FILTER PREDICATE [sec].[RestrictApplicationsByUser]([ApplicationId]) ON [app].[Applications]
WITH (STATE = ON, SCHEMABINDING = ON)
GO
Таблицы установлены следующим образом:
[app].[Applications]
имеет ApplicationId
а также Name
как столбцы, и [usr].[UserApplications]
имеет UserId
а также ApplicationId
как столбцы.
Идея в том, что всякий раз, когда пользователь запрашивает [app].[Applications]
таблица, он будет видеть только те приложения, которыми он управляет (это отношение установлено на [usr].[UserApplications]
Таблица). Насколько я могу сказать, это работает.
Теперь проблема в том, что вставка новой записи на [app].[Applications]
наряду с его ассоциацией в [usr].[UserApplications]
таблица выдает 500 ошибок сервера.
Используя SQL Profiler, я заметил, что всякий раз, когда я пытаюсь сделать запрос POST, эти два запроса выполняются в следующем порядке:
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [app].[Applications] ([Name])
VALUES (@p0);
SELECT [ApplicationId]
FROM [app].[Applications]
WHERE @@ROWCOUNT = 1 AND [ApplicationId] = scope_identity();
',N'@p0 nvarchar(2000)',@p0=N'test''
go
А также
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [usr].[UserApplications] ([UserId], [ApplicationId])
VALUES (@p1, @p2);
',N'@p1 uniqueidentifier,@p2 int',@p1='<user_guid>',@p2=<PK_value>
go
Мой недостаток опыта говорит о том, что первый запрос является атомарной операцией, поэтому, когда он пытается выбрать ApplicationId
если происходит сбой, поскольку между ним и запрашивающим пользователем нет существующей связи, так как он еще не был создан (это будет второй запрос). После прочтения немного кажется, что этот конкретный SELECT выполняется Entity Framework для получения следующего доступного идентификатора в таблице.
Если вы все еще со мной, и то, что я понял правильно, я считаю, что у меня проблемы с курицей или яйцом.
Это то, что можно исправить? Если так, где я должен искать корень проблемы? Политика RLS? Мой код API?
Большое спасибо за любой намек или совет, который вы можете дать мне.