Составной первичный ключ / головные боли от внешнего ключа

#c# #asp.net #sql-server-2008 #foreign-keys #composite-primary-key

#c# #asp.net #sql-server-2008 #внешние ключи #составной первичный ключ

Вопрос:

Я работаю с 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. Вам не следует редактировать свой вопрос, чтобы задать совершенно другой вопрос: вместо этого опубликуйте его как новый вопрос.

Ответ №1:

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

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

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

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

введите описание изображения здесь

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

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

Чтобы записать количество обращений, первое, что я бы сделал, это просто написать представление или фрагмент SQL, подобный следующему:

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

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

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

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

Метод запуска:

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

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

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

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

Комментарии:

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

2. Рад, что у вас все заработало. Существует несколько способов достижения этой цели, но иногда легко втянуться в выполнение с одной таблицей большего, чем они могут эффективно обработать. Удачи