AMO - 使用 foreach 循环基于 SQL 查找动态删除分区

AMO - Dynamically dropping partition based on SQL lookup using foreach loop

我正在尝试构建一个 SSIS 脚本任务,该任务将根据数据库视图中的分区列表检查 SSAS 多维数据集上的分区名称。如果分区存在但不在列表中,则丢弃,否则处理。

就分区 被删除而言,该脚本似乎可以正常工作,但它似乎无法继续循环并在删除时生成枚举错误,如下所示:

运行 脚本仅尝试处理(即 rowCount == 1pt.Process(),没有 else 条件)工作正常并且没有错误地完成。看来我无法在循环遍历它的集合时删除分区。如果在 SQL 查找 table.

中找到这些分区,我将不胜感激。
   public void Main()
    {
        try
        {
            String Server = Dts.Variables["User::Connection"].Value.ToString();
            String Cube = "CubeName";
            String conn = "Provider=MSOLAP;Data Source=" + Server + ";";


            Server MDXServer = new Server();
            MDXServer.Connect(conn);

            foreach (Database db in MDXServer.Databases)
            {
                foreach (Cube cb in db.Cubes)
                {
                    if (cb.Name == Cube)
                    {
                        foreach (MeasureGroup mg in cb.MeasureGroups)
                        {
                            foreach (Partition pt in mg.Partitions)
                            {
                                string PartName = (pt.Name.ToString());

                                //Create SQL query to reference the parition view and check row count when partition name used in predicate:
                                string sqlString = "SELECT COUNT(*) FROM [dim].[Partitions] WHERE [FinWeek] = @pt;";
                                // Open DB connection:
                                ConnectionManager cm;
                                cm = Dts.Connections["FIP_Server_Alias"];
                                SqlConnection connection = (SqlConnection)cm.AcquireConnection(Dts.Transaction);
                                // Link the query and the connection string together as a command
                                SqlCommand cmd = new SqlCommand(sqlString, connection);
                                // Add a value to the parameter in the SQL query
                                cmd.Parameters.AddWithValue("@pt", PartName);


                                // Activate reader to read the resulting data set from the query
                                SqlDataReader reader = cmd.ExecuteReader();

                                while (reader.Read()) //while loop performs an action whilst the reader is open
                                {
                                    // Put the second result of query (0 woudl be first) into a string variable in the script task
                                    string rowCount = reader[0].ToString();

                                    //if the partition exists but is not in the database dim.Partitions view, drop from collection.
                                    if (rowCount == "0")
                                    {
                                        pt.Drop();
                                    }
                                }
                                //End the read loop
                                reader.Close();

                            }
                        }
                    }
                }
            }
        }



        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }


        Dts.TaskResult = (int)ScriptResults.Success;
    }

它告诉你,你不能修改正在循环的集合,而你正在循环它。

因此,解决此问题的一种方法是在 foreach 循环中时不要删除分区。而是将其添加到数组或字符串生成器或您选择的其他新创建的集合中。

然后在 foreach 循环之后,遍历您新创建的集合,并删除与集合的每个成员关联的分区。

这是我在 Tab Alleman 的 steer 中找到的将其添加到集合中的解决方案。在我查询完服务器本身后,分区列表在第二个 foreach 循环中循环。我创建了一个新的 XmlaWarningCollection 并从那里删除,这似乎保持了连接。它会删除所有未在我的数据库视图中列出的分区。

可以在此 Microsoft 博客上找到更多帮助: https://blogs.msdn.microsoft.com/rafats/2009/02/10/how-to-partition-cube-using-c/

    public void Main()
    {
        try
        {
            String Server = Dts.Variables["User::Connection"].Value.ToString();
            String Cube = "TestCube";
            String conn = "Provider=MSOLAP;Data Source=" + Server + ";";


            Server MDXServer = new Server();
            MDXServer.Connect(conn);

            //Add collection to contain partitions to be dropped
            List<Partition> partitions = new List<Partition>();

            foreach (Database db in MDXServer.Databases)
            {
                foreach (Cube cb in db.Cubes)
                {
                    if (cb.Name == Cube)
                    {
                        foreach (MeasureGroup mg in cb.MeasureGroups)
                        {
                            foreach (Partition pt in mg.Partitions)
                            {
                                string PartName = (pt.Name.ToString());

                                //Create SQL query to reference the parition view and check row count when partition name used in predicate:
                                string sqlString = "SELECT COUNT(*) FROM [dim].[Partitions] WHERE [Partition] = @pt;";
                                // Open DB connection:
                                ConnectionManager cm;
                                cm = Dts.Connections["Server_Alias"];
                                SqlConnection connection = (SqlConnection)cm.AcquireConnection(Dts.Transaction);
                                // Link the query and the connection string together as a command
                                SqlCommand cmd = new SqlCommand(sqlString, connection);
                                // Add a value to the parameter in the SQL query
                                cmd.Parameters.AddWithValue("@pt", PartName);

                                // Activate reader to read the resulting data set from the query
                                SqlDataReader reader = cmd.ExecuteReader();

                                while (reader.Read()) //while loop performs an action whilst the reader is open
                                {
                                    // Put the result of query into a string variable in the script task
                                    string rowCount = reader[0].ToString();

                                    //if the partition exists but is not in the database dim.Partitions view, drop from collection.
                                    if (rowCount == "0")
                                    {
                                        partitions.Add(pt);
                                    }
                                }
                                //End the read loop
                                reader.Close();
                                }
                        }
                    }
                }
            }
            //Loop through the collection created in the above foreach loop and drop the partitions in it from the server.
            foreach (Partition dropPartition in partitions)
            {
                XmlaWarningCollection warningColln = new XmlaWarningCollection();
                dropPartition.Drop(DropOptions.Default, warningColln);
            }
         Dts.TaskResult = (int)ScriptResults.Success;
        }



          catch (Exception ex)
        {
            //catch error and return error to package for logging 
            Dts.Events.FireError(0, "Script task error: ", ex.Message + "\r" + ex.StackTrace, String.Empty, 0);
            Dts.TaskResult = (int)ScriptResults.Failure;  
        }



    }