如何使用SMO与SQL Server删除并重新创建主键索引?

YWE*_*YWE 7 .net c# smo sql-server-2005

我正在使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我尝试创建索引时,我得到一个异常,消息"无法访问Microsoft.SqlServer.Management.Smo.Index'[PK_table1]'的属性或方法,因为它已被删除." 那么有没有一种方法可以完成我想用SMO做的事情?

我在使用Index的Script方法删除索引之前尝试编写索引脚本,但它抛出了一个异常,消息"索引'PK_table1'引用了不存在的列'[table1].[owner]'." 所有者专栏明确存在.

8kb*_*8kb 5

我能够删除主键,更改列数据类型,并使用以下代码重新创建主键:

// 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);
    }                
} 
Run Code Online (Sandbox Code Playgroud)

一些警告:

  1. 如果存在没有索引的表,则定义pk的行将抛出异常
  2. 如果表由模式绑定视图引用,则删除主键将失败
  3. 如果表由外键约束引用,则删除主键将失败
  4. 如果在非聚簇索引中使用该列,则更改列的数据类型将失败
  5. 如果您有一个非常大的表,则删除聚簇主键会将表转换为堆.删除聚簇索引所花费的时间将表明进程已失败(实际上,它仍在运行)
  6. 据推测,在执行索引脚本之后,您需要使用代码清空StringCollection


blo*_*ish 0

索引对象可能已经丢失了对表的引用。您是否尝试过将索引添加回表对象?

table.Indexes.Add(pk);
Run Code Online (Sandbox Code Playgroud)