Adatis BI Blogs

PerformancePoint Planning: Deleting a Custom Member Property - A Solution

I had a bit of a rant yesterday about the fact I have had to compromise naming member properties when I've inadvertently created them with the wrong data type.  As I mentioned, I found a Dimension attribute collection method in the Planning client assemblies that hinted that it might allow me to delete a member property so I decided to give it a go. Below is some really rough and ready C# code that actually does delete a dimension member property.  I will improve the code and probably add it in to my PPSCMD GUI interface as a 'feature pack' bonus at some stage, however, if you are in desperate need for the code to delete a member property, and you can't wait for PPSCMD GUI v0.2 or PerformancePoint Version 2 (I'm not sure which will come first !) the code is below (Use at your own risk !!) Note:  Replace "MyApp", "MyDimension", "MyAttribute", oh, and the server address, accordingly.. using Microsoft.PerformancePoint.Planning.Client.Common; using Microsoft.PerformancePoint.Planning.Bmo.Core; .. // Setup the PPS Application Metadata Manager ServerHandler serverHandler = new ServerHandler("http://localhost:46787"); MetadataManager manager = new MetadataManager(); manager.ServerHandler = serverHandler; manager.ServerHandler.Connect(); // Get the system metadata BizSystem system = manager.GetSystem(true); // Get hold of the PPS Application BizApplication ppsApp = system.Applications["MyApp"]; // Obtain the root model site from the application BizModelSite site = ppsApp.RootModelSite; // Obtain the dimension that contains the member property BizDimension dimension = site.Dimensions["MyDimension"]; // Obtain the member property BizDimensionAttribute attribute = dimension.Attributes["MyAttribute"]; // Check out the dimension manager.CheckOut(dimension.Id, dimension.ParentModelSite.Id); // Perform the delete dimension.DeleteDimensionAttribute(attribute, null); // Submit the change manager.SubmitModelSite(ppsApp.Id, dimension.ParentModelSite, Microsoft.PerformancePoint.Planning.Bmo.Interfaces.SubmissionType.Update); // Check in the dimension manager.CheckIn(dimension.Id, dimension.ParentModelSite.Id); Update:  I've since discovered that you can obtain an unsupported utility from Microsoft Support that reportedly does the same thing, doh ! Oh well, always nice to have the code ..J

PerformancePoint Planning: Deleting a Custom Member Property..

Update:  I've posted a solution to Deleting a Custom Member Property here I've done this countless times; I've created my perfectly named Custom Member Property when it suddenly dawns on me that I've forgotten to give it the right data type.  No problem, right?  Wrong!  From within PBM, can you change the data type?  No!  Can you delete the member property? No!  Can you rename the member property?  No! So, what are the options?  Well, you could wait for version 2 (I truly hope you can edit/delete member properties in V2!), you could hack the back end database in the vague hope of removing the member property safely, or, as I have been doing in the past, create a new member property with a less than perfect name and try not to clench teeth and fists every time I glance at the original. Well, I've had enough, and decided I'm going to take action. Strangely, the Microsoft.PerformancePoint.Planning.BMO assembly contains a method called DeleteDimensionAttribute on the Dimension attribute collection.  I wonder... Anyone tried?

MDX Stored Procedures (Part 1)

UPDATE:  You can find part 2 here, along with a link to download a C# quick start.  A long time ago I realised that inevitably, however well specified the requirements or however tight the deadlines are, clients always throw a curve ball.  To that avail, like many, I adopt an agile approach to project delivery with a keen eye on building frameworks and generic components that improve productivity and flexibility for current and future projects. My current project is no different to any other, we knew the requirements would change as, even from the outset, they were high level and vague.  With little budget to flesh them out, a controlled, iterative approach was essential.  It's a typical BI project, various data sources require consolidating and processing to allow analytics and reporting to assist in strategy and revenue generation. The reporting element was the vaguest of them all, although what did exist immediately eliminated using Reporting Services as the reporting/delivery mechanism.  The required reports were highly interactive and aesthetically challenging enough to stretch Reporting Services functionality to the limit, even without the vagueness busting curve balls out of sight but already primed for deployment. With all this in mind, we decided to use ASP.NET 2.0 web forms for the reporting as this gave us a little more freedom with regard to layout, a high degree of flexibility surrounding interactivity and the ability to quickly react to the ever changing requirements.  Now, with an eye on productivity we decided to build an MDX Helper class (mentioned previously here and here) that would streamline the development process and enable us to react quickly to those inevitable changes. Our own requirements for such a component were as follows: Allow text files containing parameterised MDX to be executed. Must support the execution of multiple queries over a single connection Return a conventional ADOMD cell set object containing the query results Return a typed/untyped ADO.NET DataTable object for binding to native and third party .NET controls Allow the inspection of various server, database and cube properties Lightweight, re-usable and simple to use The public interface of the resultant component looks like this: In it's simplest form, usage is straight forward. Take the following parameterised query stored in file UKSales.txt select    [Product].[Product Categories].[Category].members on rows,    [Measures].[Internet Sales Amount] on columnsfrom    [Adventure Works]where    @Country You return an ADOMD cell set object using the following C# code snippet: // Create an instance of the helper class, setting cube and query informationMDXHelper helper = new MDXHelper("ASTestServer", "Adventure Works DW", "Adventure Works", MDXHelper.MDXResourceFormat.RelativeURL, "UKSales.txt");// Add in the country parameter helper.Parameters.Add("@Country", "[Geography].[Geography].[Country].&[United Kingdom]");// Execute the queryCellSet result = helper.ExecuteCellSet();// Tidy uphelper = null; There are several overrides on the constructor and 'Execute' methods to allow for flexible usage and it's been used in anger now for a good couple of weeks supporting every type of MDX query we've managed to throw at it so far.  It still needs a little refinement and some full-on testing but it has achieved its goal and has helped us easily digest changes to the original requirements.  It has also given us some great ideas for version 2 where the query definitions are stored in the Analysis Services cube definition itself. In a future post I'll delve into the approach and implementation of the helper class to see how it works under the hood.

Intellisense for ASP.NET 2.0 Skin files

Intellisense has been improved massively in Visual Studio 2005 but I noticed one file type where Intellisense is not active.  .skin files, for theming your application, do not support intellisense natively.  You can however configure Visual Studio to provide intellisense for .skin files.  Here's how:   1. Go to Tools->Options menu.2. Pick Text Editor -> File Extesion fom a tree at the left part of Options dialog.3. Type skin in Extesion text box.4. Select User Control Editor from Editor dropdown.5. Click Add and then Ok to close dialog and re-open your skin files.

LoadControl Changes in .NET 2.0

In .Net 1.x you can dynamically load user controls using the Page.LoadControl member.  Providing you namespace your classes the same or qualify the classes correctly you can cast the return value of LoadControl to an object of your user control type.   MyUserControl myUserControl = (MyUserControl )LoadControl("MyUserControl.ascx"); MyFolderedUserControl myFolderedUserControl = (MyFolderedUserControl )LoadControl("Folder/MyUserControl.ascx");   Moving to .Net 2.0, where namespaces are no longer a key reference mechanism, an additional step is required.   In the partial code behind class, specify the loading and casting as you would in Net 1.x.   MyUserControl myUserControl = (MyUserControl)LoadControl("MyUserControl.ascx"); MyFolderedUserControl myFolderedUserControl = (MyFolderedUserControl)LoadControl("Folder/MyUserControl.ascx");   However, when you attempt to compile this code, the second line will fail, this is because the foldered user control is not part of the main assembly and the compiler knows nothing about it.  To fix this you need to add a reference attribute to the aspx file that will host the user control: <%@ Reference Control="Folder/MyUserControl.ascx" %>