Вам будет нужна некоторая абстрактная фабрика одного вида или другого для перекладывания ответственности на:
interface Factory<E> {
E create();
}
class SomeContainer<E> {
private final Factory<E> factory;
SomeContainer(Factory<E> factory) {
this.factory = factory;
}
E createContents() {
return factory.create();
}
}
Вы не можете изменить тип данных с smalldatetime на datetime с указанными индексами, уникальными ограничениями, ограничениями внешнего ключа или проверочными ограничениями. Вам придется отбросить их все, прежде чем менять тип. Затем:
alter table T alter column TestDate datetime not null
Затем воссоздайте ограничения и индексы, которые все еще применяются.
Некоторые различные подходы к генерации отбрасывания и создания:
1) Если вы дали явные имена всем индексам и ограничениям, то ваш установщик может запустить статический сценарий в каждой среде (разработка, тестирование, приемочное тестирование пользователей, тестирование производительности и т. д., производство).
Чтобы сгенерировать этот явный сценарий, вы можете: a) Используйте SSMS (или SQL Server 2000, менеджер предприятия) для создания сценария операторов create и drop. б) Работайте из репозитория исходного кода, чтобы обнаружить имена и определения зависимых объектов и собрать соответствующий статический сценарий. c) Попытка запустить оператор alter. Посмотрите, на чем это не удается. Найдите определения и вручную напишите каплю и создайте. (Лично это было бы хорошо для записи перетаскивания, но не для создания.)
2) Если вы не указали явные имена для всех индексов и ограничений, то вашему установщику придется запросить словарь данных для подходящие имена и использование динамического SQL для запуска отбрасывания в правильном порядке перед оператором alter column, а затем создает в правильном порядке после alter column.
Это будет проще, если вы знаете, что есть без ограничений, только индексы.
Могут быть инструменты или библиотеки, которые уже знают, как это сделать.
Кроме того, если это пакетное приложение, вы не можете быть уверены, что локальные администраторы баз данных не добавили индексы.
ПРИМЕЧАНИЕ. Если есть уникальное ограничение,
Если вы просто меняете размер, индекс все равно останется в таблице.
Если вы меняете тип данных, вы получите сообщение об ошибке, в котором говорится, что объекты зависят от столбец, который вы пытаетесь изменить, и поэтому вы не сможете его изменить.
Вы можете создать скрипт для рассматриваемых индексов вручную или с помощью скрипта. В SSMS щелкните таблицу правой кнопкой мыши и создайте сценарий для рассматриваемого объекта.
Если вам нужен программный индексный скрипт, вот хранимая процедура, которую я использовал, которую я получил от моего бывшего коллеги.
Drop Proc ScriptIndex
GO
Create Proc ScriptIndex
@TableName VarChar (Max),
@IndexScript VarChar (Max) OUTPUT
AS
-- Get all existing indexes, EXCEPT the primary keys
DECLARE cIX CURSOR FOR
SELECT OBJECT_NAME(SI.Object_ID), SI.Object_ID, SI.Name, SI.Index_ID
FROM Sys.Indexes SI
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
ON SI.Name = TC.CONSTRAINT_NAME
AND OBJECT_NAME(SI.Object_ID) = TC.TABLE_NAME
WHERE 1=1
AND OBJECT_NAME(SI.Object_ID) = @TableName
AND TC.CONSTRAINT_NAME IS NULL
AND OBJECTPROPERTY(SI.Object_ID, 'IsUserTable') = 1
ORDER BY OBJECT_NAME(SI.Object_ID), SI.Index_ID
DECLARE @IxTable SYSNAME
DECLARE @IxTableID INT
DECLARE @IxName SYSNAME
DECLARE @IxID INT
-- Loop through all indexes
OPEN cIX
FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID
WHILE (@@FETCH_STATUS = 0)
BEGIN
DECLARE @IXSQL NVARCHAR(4000)
DECLARE @PKSQL NVARCHAR(4000)
SET @PKSQL = ''
SET @IXSQL = 'CREATE '
-- Check if the index is unique
IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsUnique') = 1)
SET @IXSQL = @IXSQL + 'UNIQUE '
-- Check if the index is clustered
IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsClustered') = 1)
SET @IXSQL = @IXSQL + 'CLUSTERED '
SET @IXSQL = @IXSQL + 'INDEX ' + @IxName + ' ON ' + @IxTable + '('
-- Get all columns of the index
DECLARE cIxColumn CURSOR FOR
SELECT SC.Name
FROM Sys.Index_Columns IC
JOIN Sys.Columns SC ON IC.Object_ID = SC.Object_ID AND IC.Column_ID = SC.Column_ID
WHERE IC.Object_ID = @IxTableID AND Index_ID = @IxID
ORDER BY IC.Index_Column_ID
DECLARE @IxColumn SYSNAME
DECLARE @IxFirstColumn BIT SET @IxFirstColumn = 1
-- Loop throug all columns of the index and append them to the CREATE statement
OPEN cIxColumn
FETCH NEXT FROM cIxColumn INTO @IxColumn
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF (@IxFirstColumn = 1)
SET @IxFirstColumn = 0
ELSE
SET @IXSQL = @IXSQL + ', '
SET @IXSQL = @IXSQL + @IxColumn
FETCH NEXT FROM cIxColumn INTO @IxColumn
END
CLOSE cIxColumn
DEALLOCATE cIxColumn
SET @IXSQL = @IXSQL + ')'
-- Print out the CREATE statement for the index
PRINT @IXSQL
FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID
END
CLOSE cIX
DEALLOCATE cIX
GO
Declare @TableName VarChar (Max), @IndexScript VarChar (Max)
Exec ScriptIndex 'Client', @IndexScript OUTPUT
Print @IndexScript
РЕДАКТИРОВАТЬ : Это зависит от исходного и измененного типа данных. Если вы попытаетесь изменить столбец с varchar на nvarchar, это не удастся. Принимая во внимание, что если вы измените столбец с varchar (16) на varchar (32), это будет успешным.
--Disable Index
ALTER INDEX MyIndex ON MyTable DISABLE
GO
-- Change column datatype
--Enable Index
ALTER INDEX MyIndex ON MyTable REBUILD
GO
Если вы измените тип столбца, тогда все индексы, которые используют этот столбец, придется перестроить.
Но если у вас нет огромных объемов данных (или вы не работаете круглосуточно и без выходных), восстановление индексов не составит большого труда. Просто запланируйте перерыв на техническое обслуживание.