Составной Первичный ключ / Головные боли Внешнего ключа - PullRequest
3 голосов
/ 07 мая 2011

Я работаю с SQL Server 2008 R2, C # и ASP.Net.У меня есть таблица с составным первичным ключом, состоящим из номера заявки и количества раз, когда эта заявка появляется в таблице.Частота тикетов рассчитывается с помощью кода C #:

VTTTickets.InsertParameters[0].DefaultValue = VTTTTicketNoBox.Text;
string CommString = "SELECT COUNT(*) FROM [Tickets] WHERE [Ticket_No] = " + 
VTTTTicketNoBox.Text;
string ConnString = ConfigurationManager.ConnectionStrings[1].ConnectionString;
OdbcConnection Conn = new OdbcConnection(ConnString);
Conn.Open();
OdbcCommand FooCommand = newOdbcCommand(CommString,Conn);
int FooVal = Convert.ToInt32(FooCommand.ExecuteScalar()) + 1;
VTTTickets.InsertParameters[1].DefaultValue = Convert.ToString(FooVal);
VTTTTicketNoBox.Text = "";
Conn.Close();

Код ограничения моих таблиц / etc

CONSTRAINT [PK_Tickets] PRIMARY KEY CLUSTERED 
([Ticket_No] ASC, [Ticket_Sub_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
CONSTRAINT [Unique_Ticket_No] UNIQUE NONCLUSTERED 
([Ticket_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,     
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
) ON [PRIMARY]
GO

Причина уникального ограничения заключается в том, что эта часть первичного составного ключатакже внешний ключ для двух других таблиц.Ошибка, которую я продолжаю получать, - это когда на меня кричат, что в столбце уникальных ограничений присутствуют повторяющиеся значенияЭто может произойти, как только все перейдет к производству из разработки, так как заявка может быть повторно отправлена.

Есть ли способ сделать внешний ключ без ограничения уникального ключа?Если нет, то как мне обойти эту проблему?

1 Ответ

4 голосов
/ 08 мая 2011

Это одна из тех ситуаций, с которыми мы часто сталкиваемся в программировании.Technology_A не позволит мне выполнить Operation_B, но так и должно быть!Затем, после того как мы некоторое время бьем головой о стену, мы сдаемся (или идем в Stackoverflow).Мы делаем это, потому что мы не используем технологию, как было задумано (это нормально, вот как мы учимся!)

Проблема здесь в схеме вашей базы данных.

Вы пытаетесь сделать слишком много за одним столом.Вы не должны хранить билеты (где один и тот же билет может существовать более одного раза) в той же таблице, в которой вы отслеживаете # случаев.

По моему мнению, есть две хорошие стратегии для исправления этой ситуации.Во-первых, я бы создал таблицу заявок с первичным ключом из одного столбца.Затем я создал бы таблицу, в которой хранится каждый экземпляр заявки.

enter image description here

Пример: Ticket43 закрыт, но снова открыт и снова закрыт.Это означает (если я правильно прочитал ваш вопрос), что у билета было два экземпляра.Это означает, что в исходной таблице будет две записи, но в моей новой предлагаемой схеме будет одна запись в Tickets и две записи в Ticket_Instances.

Примечание. Вы обязательно захотите сохранить тикетинформация, которая никогда не меняется между экземплярами в Tickets и специфическая для экземпляра информация Ticket в Ticket_Instances.

Чтобы записать количество билетов , первое, что я хотел бы сделать, это просто написать представление или бит SQLнапример:

SELECT
  count(*) as TicketCount,
  TicketID
FROM
  Ticket_Instances as TI
GROUP BY
  TicketID

Если вы не хотите рассчитывать это по требованию , тогда я предлагаю использовать:

  • ASP.NET Cache (Запустите приведенный выше SQL, закройте его в кеш с TTL 10 минут)
  • Используйте таблицу Ticket_Counts, которая заполнена триггером

Я подозреваю, что вы предпочтете вариант2 там (хотя я бы использовал вариант 1).

Метод триггера:

Предполагая, что Ticket_Instances никогда не могут быть удалены, вам нужен только триггер вставки.Вы должны создать триггер в таблице Ticket_Instances после вставки, и этот триггер SQL будет делать следующее:

  • Если TicketID не существует в Ticket_Counts, тогда вставьте TicketID в Ticket_Counts с TicketCount 0
  • Затем увеличьте TicketCount на 1 от идентификатора TicketID в Ticket_Counts

. С помощью этого метода вам нужно только получить доступ к Ticket_Counts по TicketID, чтобы получить # вхождений этого конкретного Ticket.

Я думаю, вы обнаружите, что ваши ошибки ограничения исчезают после обновления схемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...