Вопрос: Каковы некоторые другие стратегии относительно предотвращения магических чисел или трудно кодированных значений в Ваших сценариях SQL или хранимых процедурах?
Рассмотрите хранимую процедуру, задание которой состоит в том, чтобы проверить/обновить значение записи на основе StatusID
или некоторая другая таблица поиска FK или диапазон значений.
Рассмотрите a Status
таблица, где идентификатор является самым важным, поскольку это - FK к другой таблице:
Сценарии SQL, которых нужно избежать, являются чем-то как:
DECLARE @ACKNOWLEDGED tinyint
SELECT @ACKNOWLEDGED = 3 --hardcoded BAD
UPDATE SomeTable
SET CurrentStatusID = @ACKNOWLEDGED
WHERE ID = @SomeID
Проблема здесь состоит в том, что это не портативно и явно зависит от трудно кодированного значения. Тонкие дефекты существуют, когда развертывание этого к другой среде с идентификационными данными вставляет прочь.
Также стараться избегать a SELECT
на основе текстового описания/имени состояния:
UPDATE SomeTable
SET CurrentStatusID = (SELECT ID FROM [Status] WHERE [Name] = 'Acknowledged')
WHERE ID = @SomeID
Вопрос: Каковы некоторые другие стратегии относительно предотвращения магических чисел или трудно кодированных значений в Ваших сценариях SQL или хранимых процедурах?
Некоторые другие мысли о том, как достигнуть этого:
bit
столбец (названный как 'IsAcknowledged') и ряды правил, где может быть только одна строка со значением 1
. Это помогло бы в нахождении уникальной строки: SELECT ID FROM [Status] WHERE [IsAcknowledged] = 1)
На каком-то уровне будет некоторая "жесткая кодировка" значений. Идея их устранения звучит с двух сторон:
"Признано"
, а не 3
, это , вероятно, сделает ваши намерения более очевидными для читателя. Сделать столбцы bit
для различных состояний может быть хорошей или плохой идеей; на самом деле, это зависит только от данных. Если данные проходят через различные "стадии" (получение, признание, рассмотрение, отклонение, принятие, ответ и т.д.), то такой подход быстро выводит себя из-под контроля (не говоря уже о раздражающем процессе, связанном с тем, что -только один столбцов в любой момент времени установлен на 1). Если же, с другой стороны, состояние действительно настолько простое, как Вы описываете, то это может сделать код более читабельным и индексы будут работать лучше.
Самым большим "нет-нет" в жестком кодировании значений является жесткое кодирование значений, которые ссылаются на другие объекты (другими словами, жесткое кодирование первичного ключа для соответствующего объекта). Строка 'Acknowledged
' все еще является жестко закодированным значением, она просто более прозрачна по своему значению и не является ссылкой на что-то другое. Для меня она сводится к этому: если вы можете (разумно) посмотреть на него, сделайте это . Если вы не можете (или если что-то делает это неразумной задачей либо с точки зрения производительности, либо с точки зрения удобства обслуживания), то это жесткий код. Используя это, вы можете найти значение 3, используя Acknowledged
; вы не можете найти Acknowledged
ни от чего другого.
Если ваш случай так же прост, как и выше, где сработает бит IsAcknow, я пойду по этому маршруту. У меня никогда не было проблем с этим. Если у вас есть более сложные сценарии, в которых вы получите дюжину битовых полей, то я не вижу никаких проблем с использованием "магического числа", пока вы полностью им управляете. Если вас беспокоит неправильное отображение столбца идентификации при портировании базы данных, вы можете создать другой (неидентифицированный) уникальный столбец со значениями ID, целое или направляющее, или что-то еще, что может быть полезно
.Ну, начнем с того, что Бизнес-логики , вероятно, следует избегать на уровне хранилища.
Поскольку это кажется неизбежным при использовании БД, например, Sql Server, где много BL может существовать в DB, я думаю, вам лучше вернуться к использованию строковых идентификаторов , а не автоматических идентификаторов .
Это будет намного больше файловых ручек, чем автоидентификаторов, и может быть обработано лучше, даже при использовании реального прикладного уровня.
Например, используя .Net подход, можно хранить множество уникальных идентификаторов строк в любом месте, начиная с конфигурационных файлов , и заканчивая дополнительными поисками с помощью выбранных db, XML файлов.
.Для таких ситуаций, как ваша таблица состояния, я создаю так называемые "статические" наборы данных. Эти таблицы содержат данные, которые
То есть, в то же самое время вы создаете таблицу, вы также заполняете ее, используя скрипт, чтобы гарантировать, что значения всегда одни и те же. После этого, независимо от того, где и когда база данных, вы будете знать , каковы значения, и может жестко закодировать соответственно и надлежащим образом. (Я бы никогда не использовал суррогатные ключи или свойство столбца идентификации в этих ситуациях.)
Вы не должны использовать числа, вы можете использовать строки -- или двоичные файлы, или даты, или что угодно простое, легкое и наиболее подходящее. (Когда я могу, я использую строки типа char - а не варвары - такие как "RCVD", "DLVR", ACKN и т.д. - это более простые жестко закодированные значения, чем, скажем, 0, 2 и 3.)
Эта система работает для нерасширяемых наборов значений. Если эти значения могут быть изменены (так что 0 больше не означает "квитирование", то у вас проблема с безопасностью доступа. Если у вас есть система, в которой новые коды могут добавляться пользователями, то вам нужно решить другую и сложную конструкторскую проблему
.Недавно я выяснил, что магические числа могут быть реализованы видами:
CREATE VIEW V_Execution_State AS
SELECT 10 AS Pending, 20 AS Running, 30 AS Done
DECLARE @state INT
SELECT @state = Pending FROM V_Execution_State
Вот как я бы это сделал. (Потому что это намного быстрее, чем ваш пример)
UPDATE SomeTable
SET CurrentStatusID = [Status].[ID]
FROM SomeTable
RIGHT JOIN [Status] ON [Name] = 'Acknowledged'
WHERE SomeTable.[ID] = @SomeID
(не протестированные могут иметь опечатки)
.Не полагайтесь на IDENTITY для всех ваших удостоверений личности. Когда у вас есть, например, таблица поиска, которая будет состоять менее чем из 50 строк, то вполне разумно либо определить эти поиски как имеющие определенные ID, либо использовать для них строковый код. В любом случае, "жесткое кодирование" больше не является проблемой
.Одна идея:
CREATE FUNC dbo.CONST_ACKNOWLEDGED()
RETURNS tinyint
AS
BEGIN
RETURN 3
END
Однако, это имеет смысл только в том случае, если у вас нет автономера, IMHO
.] Если сущность 'Статус', которая является частью вашей доменной модели, имеет предопределенные значения, некоторые из которых должны быть обработаны определенным образом хранимыми процедурами, то совершенно нормально жестко закодировать ссылки на эти конкретные значения в вашем коде. Проблема здесь заключается в том, что вы путаете то, что потенциально является абстрактным ключом (столбец идентификатора ID) для значения, которое имеет значение в вашей доменной модели. Хотя сохранять столбец ID ID идентичности нормально, следует использовать значимый атрибут вашего доменного объекта, когда вы ссылаетесь на него в коде, это может быть имя, или это может быть числовой псевдоним. Но этот числовой псевдоним должен быть определен в вашей доменной модели, например, 3 означает 'Acknowledged', и его не следует путать с полем абстрактного идентификатора, которое, как вы говорите, может быть столбцом идентификатора в некоторых экземплярах вашей базы данных.[
].