2016-06-10 4 views
0

У меня возникла странная проблема в SSMS.Alter Table Добавить Constraint vs Alter Table Add Check Constraint

Мой настольный дизайн сильно использует составные клавиши для обеспечения строгой и надежной ссылочной целостности во всех транзитивных отношениях - ценой нарушения BCNF, но на практике это оказывается весьма удобным, особенно с автоматическими навигационными свойствами Entity Framework на этот вопрос я опубликовал ранее: How can I enforce second-degree relationships without composite keys?).

В любом случае, у меня возникают проблемы с добавлением отношений внешнего ключа с использованием редактора диаграмм SSMS 2014.

Вот упрощенный пример моей проблемы:

CREATE TABLE Tenants (
    TenantId bigint IDENTITY(1,1) PRIMARY KEY 
) 

CREATE TABLE Shops (
    TenantId bigint, -- Is a FOREIGN KEY(Tenants REFERENCES TenantId) 
    ShopId bigint IDENTITY(1,1) 

    PRIMARY KEY(TenantId, ShopId) 
) 

CREATE TABLE Job (
    TenantId bigint, -- Is a FOREIGN KEY(Tenants REFERENCES TenantId) 
    ShopId bigint, -- Is a FOREIGN KEY(Shops REFERENCES TenantId) 
    JobId bigint IDENTITY(1,1) 

    PRIMARY KEY(TenantId, ShopId, JobId) 
) 

У меня есть много таблиц со столбцами, как эти, и используя Diagram Editor, чтобы создать отношения с ссылочной целостностью для составных ключей работает отлично (просто Ctrl + клик каждый композитный столбец FK, а затем перетащить на первичную таблицу ключей, и нажмите кнопку OK, и это все.

Однако с несколькими раз, он терпит неудачу. Например, если выбрать TenantId и ShopId в Jobs и перетащить их на к таблице Shops, это дает мне это e rror:

The columns in table 'Shops' do not match an existing primary key or UNIQUE constraint.

... даже если эти две колонки являются первичный ключ в таблице Shops!

Я получил SSMS для создания SQL для ограничения он пытается добавить, и он дал мне это (форматирование мой, дополнительный TRANSACTION код удален):

ALTER TABLE 
    dbo.Jobs 
ADD CONSTRAINT 
    FK_Jobs_Shops 
FOREIGN KEY 
    (ShopId, TenantId) REFERENCES dbo.Shops (ShopId, TenantId) 

ON UPDATE 
    NO ACTION 
ON DELETE 
    NO ACTION 

Когда я побежал прямо, SQL Server дал мне эту ошибку:

Msg 1776, Level 16, State 0, Line 1 There are no primary or candidate keys in the referenced table ' dbo.Shops ' that match the referencing column list in the foreign key ' FK_Jobs_Shops '.

Msg 1750, Level 16, State 0, Line 1 Could not create constraint or index. See previous errors.

Обратите внимание, что другие таблицы уже имели определенный внешнего ключа отношения к Shops таблице - так что я задавался вопросом, что происходит. Так что я сказал SSMS в скрипт для создания, казалось бы, рабочими ограничений - то я переименовал вещи, чтобы сделать это создать ограничение я хотел первоначально (между Jobs и Shops), и он дал мне эту разные выхода (форматирование мой):

ALTER TABLE 
    [dbo].Jobs WITH CHECK 
ADD CONSTRAINT 
    [FK_Jobs_Shops] 
FOREIGN KEY 
    ([TenantId], [ShopId]) REFERENCES [dbo].[Shops] ([TenantId], [ShopId]) 
GO 

ALTER TABLE 
    [dbo].[Jobs] 
CHECK CONSTRAINT 
    [FK_Jobs_Shops] 
GO 

Когда я побежал, это сработало!

Обратите внимание на различия:

  • Добавление WITH CHECK
  • Отсутствие ON UPDATE/ON DELETE заявления
  • Ограничение было осуществлено в двух операторов, а не один.

Мои вопросы:

  • ли я обнаружил ошибку в SQL Server?
  • Есть ли семантическая разница между двумя синтаксисами определения ограничений?
  • Вернее, почему один работает, но не другой?
+0

Вы могли видеть http://stackoverflow.com/questions/529941/with-check-add-constraint-followed-by-check-constraint-vs-add-constraint, возможно, полезно – Kiquenet

ответ

2

Единственное существенное различие между двумя сценариями - порядок полей внешнего ключа/ссылочных полей первичного ключа.

Неисправный скрипт использует (ShopId, TenantId), который не является порядок определения первичного ключа:

PRIMARY KEY(TenantId, ShopId) 

Не удалось найти официальную ссылку, но это seems, что вы должны указать поля FK в том же порядке, в определении ПК.