2012-03-17 2 views
3

Поэтому у меня есть две таблицы:Альтернатива для проверки ограничений в представлениях

Requests 
-------- 
Id 
RequestSchemeId 
ReceivedByUserId 

ForwardedRequests 
----------------- 
Id 
RequestId (FK to Id column of Requests Table) 
ForwardedToUserId 

и один вид

ForwardedRequestsInRequestSchemes 
--------------------------------- 
Requests.RequestSchemeId 
Requests.ReceivedByUserId 
ForwardedRequests.ForwardedToUserId 

Что стандарт/рекомендуемый способ добавления ограничений эквивалент для Requests.ReceivedByUserId != ForwardedRequests.ForwardedToUserId в представлении ?

Я знаю, что ограничения проверки недопустимы во взглядах. Использование SQL Server 2008.

EDIT:

Это Followup вопрос this question.

Бизнес-правила:

  1. Тот же запрос может быть пересылаются нескольким пользователям. Следовательно, столбец Идентификатор в таблице ForwardedRequests.

  2. Пользователь может получить только один запрос для конкретной RequestScheme. Поэтому я создал ограничение UniqueKey для RequestSchemeId + ReceivedByUserId в таблице запросов.

  3. Запрос может быть перенаправлен другому пользователю, только если переадресованный пользователь еще не отправил запрос по той же схеме от любого другого пользователя. Так как Мартин предложил в linked question, я создал представление из двух таблиц и добавил уникальное ограничение на Requests.RequestSchemeId + ForwardedRequests.ForwardedToUserId.

  4. Деловое правило, о котором идет речь, заключается в том, что получатель запроса не может переслать его самому себе.

+1

Почему вы не используете 'WHERE Requests.ReceivedByUserId <> ForwardedRequests.ReceivedByUserId'? – Kaf

+1

@Kaf - Это не поможет. [Дополнительный контекст вопроса здесь] (http://stackoverflow.com/q/9749902/73226) –

+0

@Martin Спасибо за добавление ссылки. – NVM

ответ

5

Я могу придумать пару способов заставить SQL Server обеспечить это для вас. Оба довольно хаки, хотя так заинтересованы, чтобы увидеть любые другие подходы.

1) Вы можете добавить в индексный вид ForwardedRequestsInRequestSchemes дополнительную колонку 1/(ForwardedToUserId - ReceivedByUserId) AS FailIfSame, которая поднимет Divide by zero error, если эти два значения совпадают. Это означает, что вы в конечном итоге сохраняете избыточный столбец в индексированном представлении.

2) Вы можете создать новое представление, которое возвращает любые такие пересечения строк, объединенные в таблицу из двух строк, а затем определить уникальное ограничение для этого представления. Это представление всегда будет пустым.

CREATE TABLE dbo.TwoRows(C INT) INSERT INTO dbo.TwoRows VALUES(1),(1) 

GO 

CREATE VIEW dbo.FailIfForwardedUserEqualToReceivedByUser 
WITH SCHEMABINDING 
AS 
    SELECT 1 AS C 
    FROM dbo.ForwardedRequests FR 
     INNER JOIN dbo.Requests R 
      ON R.Id = FR.RequestId AND R.ReceivedByUserId = FR.ForwardedToUserId 
     CROSS JOIN dbo.TwoRows 

GO 

CREATE UNIQUE CLUSTERED INDEX ix ON 
    dbo.FailIfForwardedUserEqualToReceivedByUser(C) 
+0

Перекрестные соединения AFAIK не допускаются в индексируемых представлениях. –

+0

@VitaliyKalinin - Да. Я протестировал это, и оба отлично работают, чтобы заставить SQL Server обеспечить выполнение этого требования. –

+0

Действительно, вы правы. –

3

Один из способов запретить update, insert, delete права на столах, и обеспечить соблюдение требований бизнеса с помощью хранимой процедуры. Например,

create procedure dbo.AddRequestForward(
    @requestId int 
, @forwardedToUserId int) 
as 
insert ForwardedRequests 
     (ForwardedRequests, ForwardedRequests) 
select @requestId 
,  @forwardedToUserId 
where not exists 
     (
     select * 
     from Requests 
     where Id = @requestId 
       and @forwardedToUserId = @forwardedToUserId 
     ) 

if @@rowcount = 0 
    return -1 -- Forwarded and Received identical user 
return 1 -- Success 
go 
+2

Без дополнительных указаний на блокировку у этого есть условия гонки (поэтому, как правило, лучше заставить SQL Server применять эти ограничения). –

+0

@MartinSmith: Пока в вопросе не указывается интенсивный параллельный трафик, я думаю, что это достаточно безопасно – Andomar

+1

@Andomar «Безопасный достаточно» звучит страшно. Я новичок в программировании базы данных, но думаю, было бы разумно использовать подход Мартина * уродливый *, потому что он по крайней мере никогда не пойдет не так. – NVM

Смежные вопросы