Как удалить и воссоздать индекс первичного ключа, используя SMO с SQL Server? - PullRequest
7 голосов
/ 29 июля 2010

Я использую SQL Server 2005 Express. Я хочу использовать SMO, чтобы пройтись по каждой таблице в базе данных и изменить каждый столбец Char на столбец Varchar. Если столбец является элементом первичного ключа, мне нужно сначала отбросить первичный ключ, прежде чем изменять тип данных столбца. Тогда мне нужно пересоздать индекс. Вот код, который я пытаюсь использовать:

foreach (Table table in database.Tables)
{
    Index pk = table.Indexes.Cast<Index>().SingleOrDefault(index => index.IndexKeyType == IndexKeyType.DriPrimaryKey);
    if (pk != null)
    {
        pk.Drop();
        table.Alter();
    }
    foreach (Column column in table.Columns.Cast<Column>().Where(column => column.DataType.SqlDataType == SqlDataType.Char))
    {
        column.DataType = new DataType(SqlDataType.VarChar, column.DataType.MaximumLength);
    }
    table.Alter();
    if (pk != null)
    {
        pk.Create();
    }
}

Но когда я пытаюсь создать индекс, я получаю исключение с сообщением «Не удается получить доступ к свойствам или методам для Microsoft.SqlServer.Management.Smo.Index '[PK_table1]', поскольку он был удален». Так есть ли хороший способ выполнить то, что я хочу сделать с SMO?

Я пытался создать сценарий для индексации перед тем, как удалить его, используя метод индекса Script, но он выдает исключение с сообщением «Индекс« PK_table1 »ссылается на несуществующий столбец« [таблица1]. [Владелец] ».» Столбец владельца явно существует.

Ответы [ 6 ]

5 голосов
/ 11 августа 2010

Мне удалось удалить первичный ключ, изменить типы данных столбца и заново создать первичный ключ с помощью этого кода:

// using System.Collections.Specialized;

foreach (Table table in database.Tables)
{
    // object to hold the index script
    StringCollection pk_script = new StringCollection();

    Index pk = table.Indexes.Cast<Index>().SingleOrDefault(index => index.IndexKeyType == IndexKeyType.DriPrimaryKey);
    if (pk != null)
    {
        // script the index
        pk_script = pk.Script();
        pk.Drop();
        table.Alter();
    }
    foreach (Column column in table.Columns.Cast<Column>().Where(column => column.DataType.SqlDataType == SqlDataType.Char))
    {
        column.DataType = new DataType(SqlDataType.VarChar, column.DataType.MaximumLength);
    }
    table.Alter();

    // iterate through script StringCollection
    foreach (String tsql in pk_script)
    {
        database.ExecuteNonQuery(tsql);
    }                
} 

Некоторые предостережения:

  1. Строка, которая определяет pk, бросит исключение, если есть таблица без индексов
  2. Сброс первичного ключа не удастся если на таблицу ссылается представление со схемой
  3. Сброс первичного ключа не удастся если на таблицу ссылается ограничения внешнего ключа
  4. Изменение типа данных столбца потерпит неудачу, если этот столбец используется в некластеризованный индекс
  5. Если у вас очень большой стол, отбрасывая кластерный первичный ключ преобразует таблицу в кучу. Время, необходимое для удаления Кластерный индекс предложит процесс не удался (хотя на самом деле он все еще работает)
  6. Предположительно, вам понадобится код для очистить коллекцию StringCollection после индексный скрипт был выполнен
4 голосов
/ 10 августа 2010

Попробуйте создать первичный ключ снова следующим образом.

Index index = new Index(table, "PK_tableNameTable");
index.IndexKeyType = IndexKeyType.DriPrimaryKey;

//You will have to store the names of columns before deleting the key.
index.IndexedColumns.Add(new IndexedColumn(index,"ID")); 

table.Indexes.Add(index);

Источник фрагмента

0 голосов
/ 29 марта 2011

Я столкнулся с той же проблемой, когда SMO сказал, что столбцы, используемые в индексе, не существуют.Я решил это, вызвав метод Discover () для объекта Table перед вызовом Script () для ForeignKey.Это отличается от Table.Refresh, который не читает все метаданные таблицы.Вызов Table.Discover () заметно замедляет код, но после этого происходит успешное обращение к ForeignKey.Script.Вам не нужно сохранять список, который возвращает Discover, если он вам не нужен.Но принудительное извлечение метаданных таким способом заставляет работать функцию сценариев.

0 голосов
/ 12 августа 2010

У вас есть возможность запускать сценарии SQL через SMO?Я начал запускать все сценарии, которые делают любые структурные модификации БД через ServerConnection.ExecuteNonQuery.Значительное улучшение стабильности по сравнению с обычным стеком SqlCommand и т. Д. (Также не сравнивается с GO :-) В итоге получился очень полезный синтез.Конечно, не MARS-соединение.

0 голосов
/ 05 августа 2010

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

0 голосов
/ 30 июля 2010

Возможно, объект Index потерял свою ссылку на таблицу.Вы пытались добавить индекс обратно к объекту таблицы?

table.Indexes.Add(pk);
...