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

发布于 2024-09-12 00:05:35 字数 969 浏览 2 评论 0原文

我正在使用 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 做的事情呢?

在使用 Index 的 Script 方法删除索引之前,我尝试编写索引脚本,但它抛出异常并显示消息“索引 'PK_table1' 引用不存在的列 '[table1].[owner]'”。所有者列显然存在。

I am using SQL Server 2005 Express. I want to use SMO to loop through each table in a database and change each Char column to a Varchar column. If a column is a member of the primary key, I need to first drop the primary key before altering the datatype of the column. Then I need to recreate the index. Here is the code I am trying to use:

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();
    }
}

But when I try to create the index I get an exception with the message "Cannot access properties or methods for the Microsoft.SqlServer.Management.Smo.Index '[PK_table1]', because it has been dropped." So is there a good way of accomplishing what I want to do with SMO?

I tried scripting the index before I dropped it using the Script method of Index, but it throws an exception with the message "The Index 'PK_table1' references nonexistent column '[table1].[owner]'." The owner column clearly exists.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

奶茶白久 2024-09-19 00:05:36

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

// 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
    索引脚本已执行

I was able to drop the primary key, alter the column data types, and re-create the primary key with this code:

// 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);
    }                
} 

Some caveats:

  1. The line that defines pk will throw
    an exception if there is a table
    without indexes
  2. Dropping the primary key will fail
    if the table is referenced by a schema-bound view
  3. Dropping the primary key will fail
    if the table is referenced by
    foreign key constraints
  4. Changing the data type of the column
    will fail if that column is used in
    a nonclustered index
  5. If you have a very large table,
    dropping a clustered primary key
    will convert the table to a heap.
    The time taken to to remove the
    clustered index will suggest the
    process has failed (while, in fact,
    it is still running)
  6. Presumably you would need code to
    empty the StringCollection after the
    index script was executed
权谋诡计 2024-09-19 00:05:36

尝试通过以下方式再次创建主键。

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);

代码片段来源

Try creating primary key again in the following manner.

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);

Source of the snippet

如若梦似彩虹 2024-09-19 00:05:36

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

table.Indexes.Add(pk);

Possibly the Index object has lost it's reference to the Table.
Have you tried to Add the Index back to the table object ?

table.Indexes.Add(pk);
一百个冬季 2024-09-19 00:05:36

不要删除并重新创建索引,而是尝试禁用它,然后在使用 .Disable.Enable 方法完成后重新启用它。

Instead of dropping and recreating the index, try just disabling it and then re-enabling it when you are done using the .Disable and .Enable methods.

小忆控 2024-09-19 00:05:36

您可以选择通过 SMO 运行 SQL 脚本吗?我开始运行所有通过 ServerConnection.ExecuteNonQuery 进行结构数据库修改的脚本。与通常的 SqlCommand 等堆栈相比,稳定性有了很大的提高(也不与 GO-s 相比:-)最终成为一个非常有用的融合。当然是非 MARS 连接。

Do you have an option to run SQL scripts through SMO? I started running all scripts that do any structural DB modifications via ServerConnection.ExecuteNonQuery. Big stability improvement over usual SqlCommand etc. stack (doesn't compain against GO-s either :-) Ended up being a very usefull fusion. Non-MARS connection of course.

好多鱼好多余 2024-09-19 00:05:36

我遇到了同样的问题,SMO 告诉我索引中使用的列不存在。我通过在外键上调用 Script() 之前调用 Table 对象上的 Discover() 方法解决了这个问题。这与 Table.Refresh 不同,Table.Refresh 不会读取表的所有元数据。调用 Table.Discover() 会明显减慢代码速度,但调用foreignkey.script 会成功。您不必保存 Discover 返回的列表,除非您需要它。但强制以这种方式获取元数据确实可以使脚本功能正常工作。

I ran into the same issue with SMO telling me that columns used in the index didn't exist. I solved it by calling the Discover() method on the Table object prior to calling Script() on my ForeignKey. This is different from Table.Refresh which doesn't read all of the table's metadata. Calling Table.Discover() noticably slows down the code but the call to ForeignKey.Script succeeds after doing so. You don't have to save the List that Discover returns unless you need it for something. But forcing the metadata to be fetched in this way does make the scripting function work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文