Master Data Services Excel Add-in Query updater

Hi

This small tool allows you to Load, Edit, and save MDS queries with operators that are not available in current mds add-in
232951
you can download the source code (.Net C# 4.0 Client Profile, VS2010) of my tool here (FREE) HERE
OR
binary only: HERE

very easy to use:

Load your already generated query

then choose a new Operator and edit the criteria

and then save the updated query

you can use all these operators:
[Description("")] NotSpecified,
[Description("=")] IsEqual,
[Description(“<>”)] IsNotEqual,
[Description("LIKE")] Like,
[Description("NOT LIKE")] NotLike,
[Description(“>”)] GreaterThan,
[Description("< ")] LessThan, [Description(">=")] GreaterThanOrEqual,
[Description(“< =")] LessThanOrEqual,
[Description("MATCH")] Matches,
[Description("NOT MATCH")] NotMatches,
[Description("REGEX")] ContainsPattern,
[Description("NOT REGEX")] NotContainsPattern,
[Description("IS NULL")] IsNull,
[Description("IS NOT NULL")] IsNotNull,
[Description("IN")] In,
[Description("NOT IN")] NotIn,
[Description("DIRECT DECENDANTS")] DirectDecendants,
[Description("ALL DECENDANTS")] AllDecendants,

More info on sql mds 2012 MSDN blog

Master Data Services : Display entity members with good sort order when code is numeric

a MDS user recently asked me this question:

When looking at entity contents via web UI in the column code, 10 and each code that starts with 1 (10,11..19) always goes before 2 and so on. Is there any way to fix it? I don’t believe that’s the right order.

example:

 

so I’ve started to investigate..

first (easy solution)

the easiest way is to add at least one zero before code “1” and code  “2” and so on

but if your code size is huge, you will have to add a lot of “0” behind your code

so I’ve tried to find a custom hack in MDS stored procedure: and finally I’ve found it :)

second (hard way) solution:

after a few search on google, I’ve found this post :

http://stackoverflow.com/questions/119730/how-do-i-sort-a-varchar-column-in-sql-server-that-contains-numbers

but I had to find where to place this code hack

after a few search on mds (by sorting entity members in Web UI and looking at SQL profiler)

i’ve found that a call was made to this stored procedure:

 

declare @p16 int
set @p16=NULL
declare @p17 mdm.MemberGetCriteria
exec mdm.udpEntityMembersGet @User_ID=1,@Version_ID=5,@Hierarchy_ID=NULL,@HierarchyType_ID=NULL,@ParentEntity_ID=NULL,@Entity_ID=336,@MemberType_ID=1,@ParentCode=default,@ColumnString=N'',@AttributeGroup_ID=NULL,@PageNumber=1,@PageSize=50,@SortColumn=N'Code',@SortDirection=N'ASC',@CountOnly=0,@MemberCount=@p16 output,@SearchTable=@p17
select  @p16declare @p16 int
set @p16=NULL
declare @p17 mdm.MemberGetCriteria

exec mdm.udpEntityMembersGet @User_ID=1,@Version_ID=5,@Hierarchy_ID=NULL,@HierarchyType_ID=NULL,@ParentEntity_ID=NULL,@Entity_ID=336,@MemberType_ID=1,@ParentCode=default,@ColumnString=N'',@AttributeGroup_ID=NULL,@PageNumber=1,@PageSize=50,@SortColumn=N'Code',@SortDirection=N'ASC',@CountOnly=0,@MemberCount=@p16 output,@SearchTable=@p17
select  @p16

after looking into udpEntityMembersGet, I’ve found that another stored procedure was called : mdm.udpMembersGet, a huge one!

so I’ve tried to update this SP code and finally it works!

be carefull, this hack could slow down the entitymembers get request, and it is only for testing purpose, and if you update MDS with cumulative update, it could be erased!

you just have to replace every instance of (there should be 3 of them) :

 

IF (@SortOrderColumnQuoted IS NOT NULL) BEGIN
SET @SQL += @SortOrderColumnQuoted + N' ' + @SortDirection + N', ';
  				END

by:

 

 IF (@SortOrderColumnQuoted IS NOT NULL) BEGIN  
                SET @SQL += N' CASE 
    WHEN ISNUMERIC('+@SortOrderColumnQuoted+') = 1 THEN CONVERT(INT, '+@SortOrderColumnQuoted+') 
    ELSE 9999999 -- or something huge
  END ' + N' ' + @SortDirection + N', ';  
            END

 result:

 

 right click here and ‘save as’ to download the customized stored procedure

 

Master Data Services : Business Rules Copy / Import / Export (Cross Model)

updated article (Oct 2011)

(code refactored)

Hi All,

One other missing feature of MDS is Import / Export / Copy Business rules from a model to another (or copy business rules to the same model)

my code is still in beta, but it is already (partially) working.

you can find it on my “MDS Manager” tool on codeplex:

http://mdsmanager.codeplex.com


Get business rules from modelId, quite easy with service client method “business rules get”, returns a business rule set

 public BusinessRules GetBusinessRules(string fileName)
        {
            BusinessRules brs = null;
            Stream str = null;
            try
            {

                if (File.Exists(fileName))
                {
                    str = new FileStream(@fileName, FileMode.Open, FileAccess.Read, FileShare.Read);

                    if (str == null)
                    {
                        throw new BusinessRulesException("error while opening file!");
                    }

                    XmlSerializer xs = new XmlSerializer(typeof(BusinessRules));
                    // Load the object saved above by using the Deserialize function
                     brs = (BusinessRules)xs.Deserialize(str);

                }
                else
                {
                    throw new BusinessRulesException("Cannot find specified file!");
                }

                return brs;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {

                // Cleanup                 if (str != null)
                    str.Close();

            }

        }
then we export business rules to a XML file
note:
//this is needed to avoid a serialization error (more info on http://www.johnsoer.com/blog/?p=125 ) :
 //XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(BRAttributeValueArgument),typeof(BRBlankArgument)
   //                                                                                     ,typeof(BRDomainBasedAttributeArgument)});
here is the export method :
 public void ExportBusinessRules(string exportFileName, BusinessRules brs)
        {
            TextWriter WriteFileStream = null;
            try
            {

                //new type needed to avoir error because serialization of an inherited class                 XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(Common.ServiceReference1.BRAttributeValueArgument) });
//update oct 2011!
//new type needed to avoir error because serialization of an inherited class

               XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(BRAttributeValueArgument),typeof(BRBlankArgument)
                                                                                        ,typeof(BRDomainBasedAttributeArgument)});
              // Create a new file stream to write the serialized object to a file                 WriteFileStream = new StreamWriter(@exportFileName);
                xs.Serialize(WriteFileStream, brs);

               //custom exception class , but not required              throw new BusinessRulesException("Business Rules successfully exported to file " + exportFileName);

            }
            catch (Exception exc)
            {
                throw exc;
            }
            finally
            {
               // Cleanup                 if (WriteFileStream != null)
                    WriteFileStream.Close();
            }
        }

then we would like to import this XML file to another model:
here is the method to get business rules set from a previously exported XML file :
  public BusinessRules GetBusinessRules(string fileName)
        {
            BusinessRules brs = null;
            Stream str = null;
            try
            {

                if (File.Exists(fileName))
                {
                    str = new FileStream(@fileName, FileMode.Open, FileAccess.Read, FileShare.Read);

                    if (str == null)
                    {
                        throw new BusinessRulesException("error while opening file!");
                    }

                    XmlSerializer xs = new XmlSerializer(typeof(BusinessRules));
                   // Load the object saved above by using the Deserialize function                    brs = (BusinessRules)xs.Deserialize(str);

                }
                else
                {
                    throw new BusinessRulesException("Cannot find specified file!");
                }

                return brs;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {

              // Cleanup 
          if (str != null)
                    str.Close();

            }

        }

//then we can get the source modelID
 sourceModelId =brs.BusinessRulesMember.First().Identifier.ModelId as Identifier;
// and then clone business rule set with updated modelId:
//brs is the business rule set
//sourceModelId is the source Model Identifier (taken above from the Rules set from the XML file)
//target ModelId is the model Identifier for the model we want to import back the B. rules to
CloneBusinessRules(brs,sourceModelId, targetModelId));
Here is the CloneBusinessRules Method:
public string CloneBusinessRules(BusinessRules brs, Identifier SourceModelId, Identifier targetModelId)
        {

            OperationResult or = null;
            //instanciate new BR members
            try
            {
                int cptMissingEntity = 0;
                StringBuilder sb = new StringBuilder("these business rule related entities does not exists in target model:");
                sb.AppendLine();
                BusinessRules newBRS = new BusinessRules();
                foreach (BusinessRule br in brs.BusinessRulesMember)
                {
                    Identifier EntityId = null;
                    //this is used to get the target entity Id with matching its name 
                    using (ServiceClient c = new ServiceClientWrapper().CreateServiceClient())
                    {
                        EntityId = GetEntityIdFromName(c, c.Endpoint.Address.Uri.OriginalString, targetModelId, br.Identifier.EntityId.Name);

                    }
                    if (EntityId != null)
                    {
                        newBRS.BusinessRulesMember = new Collection<BusinessRule>();

                        //create a new business rule based on the source one, and applying on it the target identifiers and names 
                        BusinessRule newBR = BusinessRuleInstanciate(Guid.NewGuid(), br.Identifier.Name, targetModelId.Name, br.Identifier.EntityId.Name,
                            br.Identifier.MemberType, br.Priority, br.BRActions, br.Identifier.InternalId, br.RuleActionText, br.RuleConditionText);
                        //some required parameters to instanciate below:

                        //instanciate BRActions
                        newBRS.BRActions = BRActionsInstanciate(brs.BRActions, newBR.Identifier);
                        //instanciate BRConditions
                        newBRS.BRConditions = BRConditionsInstanciate(brs.BRConditions, newBR.Identifier);
                        //instanciate BRConditionTreeNodes
                        newBRS.BRConditionTreeNodes = BRConditionTreeNodesInstanciate(brs.BRConditionTreeNodes, newBR.Identifier);
                        newBRS.BusinessRulesMember.Add(newBR);
                    }
                    else
                    {
                        sb.AppendLine(br.Identifier.EntityId.Name);
                        cptMissingEntity++;
                        //these business rule related entities do not exist in target model
                    }
                    //then we clone modified BRSet
                    using (ServiceClient c = new ServiceClientWrapper().CreateServiceClient())
                    {

                        or = c.BusinessRulesClone(new International(), newBRS);
                        string err = Tools.HandleErrors(or);
                        if (!string.IsNullOrEmpty(err))
                        {
                            throw new Exception(err);
                        }
                    }
                    if (cptMissingEntity == 0)
                    {
                        sb = new StringBuilder();
                    }
                }

                return sb.ToString();
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

update oct 2011 code for BRActionsInstanciate, BRConditionsInstanciate,BRConditionTreeNodesInstanciate

 private Collection<BRConditionTreeNode> BRConditionTreeNodesInstanciate(Collection<BRConditionTreeNode> BRConditionTreeNodes, MemberTypeContextIdentifier BRId)
        {

            try
            {
                //Add BRConditionTreeNode to BRConditionTreeNode Collection

                Collection<BRConditionTreeNode> newBRConditionTreeNodes = new Collection<BRConditionTreeNode>();

                foreach (BRConditionTreeNode brctn in BRConditionTreeNodes)
                {
                    BRConditionTreeNode BRConditionTreeNodeItem = new BRConditionTreeNode();
                    //Add Attribute and Action type to the collection
                    BRConditionTreeNodeItem.BRConditions = BRConditionsInstanciate(brctn.BRConditions, BRId);
                    BRConditionTreeNodeItem.BusinessRuleId = BRId;
                    BRConditionTreeNodeItem.ConditionTreeChildNodes = brctn.ConditionTreeChildNodes;
                    BRConditionTreeNodeItem.ConditionTreeParentNode = brctn.ConditionTreeParentNode;
                    BRConditionTreeNodeItem.LogicalOperator = brctn.LogicalOperator;
                    BRConditionTreeNodeItem.Identifier = new Identifier() { Name = brctn.Identifier.Name, Id = Guid.NewGuid() };

                    //All Action and Condition Items must have a sequence greater that zero
                    BRConditionTreeNodeItem.Sequence = brctn.Sequence;
                    newBRConditionTreeNodes.Add(BRConditionTreeNodeItem);
                }
                return newBRConditionTreeNodes;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        private Collection<BRAction> BRActionsInstanciate(Collection<BRAction> BRActions, MemberTypeContextIdentifier BRId)
        {

            try
            {
                //Add Action to Action Collection

                Collection<BRAction> newBRActions = new Collection<BRAction>();

                foreach (BRAction bra in BRActions)
                {
                    BRAction BRActionItem = new BRAction() { Identifier = new Identifier() { Id = Guid.NewGuid(), Name = bra.Identifier.Name }, BusinessRuleId = BRId };
                    //Add Attribute and Action type to the collection
                    BRActionItem.PrefixArgument = new BRAttributeArgument();
                    BRActionItem.PrefixArgument.PropertyName = bra.PrefixArgument.PropertyName;
                    BRActionItem.PrefixArgument.AttributeId = new Identifier();
                    BRActionItem.PrefixArgument.AttributeId.Id = Guid.NewGuid();
                    BRActionItem.PrefixArgument.AttributeId.Name = bra.PrefixArgument.AttributeId.Name;
                    BRActionItem.Operator = bra.Operator;
                    var colBRffa = new Collection<object>();
                    foreach (var brffa in bra.PostfixArguments)
                    {
                        BRBlankArgument BRba = brffa as BRBlankArgument;
                        BRFreeformArgument BRffa = brffa as BRFreeformArgument;
                        if (BRba != null)
                        {
                            colBRffa.Add(new BRBlankArgument() { Identifier = new Identifier() { Id = Guid.NewGuid(), Name = BRba.Identifier.Name }, PropertyName = BRba.PropertyName });

                        }
                        else
                        {
                            if (BRffa != null)
                            {
                                colBRffa.Add(new BRFreeformArgument() { Identifier = new Identifier() { Id = Guid.NewGuid(), Name = BRffa.Identifier.Name }, Value = BRffa.Value, PropertyName = BRffa.PropertyName });

                            }
                        }
                    }
                    BRActionItem.PostfixArguments = colBRffa;
                    BRActionItem.Text = bra.Text;

                    //All Action and Condition Items must have a sequence greater that zero
                    BRActionItem.Sequence = bra.Sequence;
                    newBRActions.Add(BRActionItem);
                }
                return newBRActions;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }
        public Collection<BRCondition> BRConditionsInstanciate(Collection<BRCondition> BRconditions, MemberTypeContextIdentifier BRId)
        {

            try
            {
                //Add Action to Action Collection

                Collection<BRCondition> newBRconditions = new Collection<BRCondition>();
                BRCondition BRConditionItem = new BRCondition();

                foreach (BRCondition brc in BRconditions)
                {
                    //Add Attribute and Action type to the collection
                    BRConditionItem.BusinessRuleId = BRId;

                    BRConditionItem.ConditionTreeNodeId = new Identifier() { Name = brc.ConditionTreeNodeId.Name };
                    BRConditionItem.Identifier = new Identifier() { Id = Guid.NewGuid(), Name = brc.Identifier.Name };
                    BRConditionItem.Operator = brc.Operator;
                    BRConditionItem.PrefixArgument = brc.PrefixArgument;
                    BRConditionItem.PostfixArguments = brc.PostfixArguments;
                    //All Action and Condition Items must have a sequence greater that zero
                    BRConditionItem.Sequence = brc.Sequence;
                    BRConditionItem.Text = brc.Text;
                    newBRconditions.Add(BRConditionItem);
                }
                return newBRconditions;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

Master Data Services : Cross Model entity Copy

Hi all,

One of the missing things in MDS is the cross-model entity copy

here is a API usage example for copying an entity from a model /version to another (or even copy an entity into a new model with a new entity name).

you can download the complete source code of my codeplex tool including this sample on : http://mdsmanager.codeplex.com

note: if source entity contains domain based attributes, and if the target model does not contain the domain based attribute parent entity, the attribute type will automatically converted to “Freeform” instead of “Domain based attribute”.

 

 private void CopyEntity(Identifier newModelId, Identifier versionId, Entity EntityToCopy)
        {
            OperationResult or = new OperationResult();

            try
            {
                Cursor.Current = Cursors.WaitCursor;

                Common.MDS_WS mds = new MDS_WS();
                //create a new guid for the new entity (target entity must NOT have the same ID than the source entity)             
    Guid newEntityId = Guid.NewGuid();

                //create a new metadata instance      
           Metadata md = new Metadata();
                md.Entities = new Collection();

                //add a new entity in this new metadata, with values and fields from source entity
                md.Entities.Add(new Entity()
                {
                    Identifier = new ModelContextIdentifier() { ModelId = newModelId, Name = !string.IsNullOrEmpty(txtNewEntityName.Text) ? txtNewEntityName.Text : EntityToCopy.Identifier.Name, Id = newEntityId },
                    AuditInfo = EntityToCopy.AuditInfo,
                    ExtensionData = EntityToCopy.ExtensionData,
                    ExplicitHierarchies = EntityToCopy.ExplicitHierarchies,
                    IsBase = EntityToCopy.IsBase,
                    IsFlat = EntityToCopy.IsFlat,
                    IsSystem = EntityToCopy.IsSystem
                });

                //publish this new entity
                using (ServiceClient c = MDS_WSConnect.CreateMdsProxy())
                {
                    Metadata retMd = c.MetadataCreate(new International(), md, true, out or);

                    //get source entity attributes
                    md = mds.GetMetaData(new International(), ref or, (Identifier)cbModel.SelectedItem, ((CustomVersion)cbVersion.SelectedItem).Identifier, EntityToCopy.Identifier, MDS_WS.MDAction.AttributesDetails);

                    //create a new metadata instance for attributes to copy
                    Metadata newMD = new Metadata();
                    newMD.Attributes = new Collection();

                    //for each source entity attribute, create a new attribute containing values and fields from this source entity
                    foreach (MetadataAttribute oldMA in md.Attributes)
                    {
                        MetadataAttribute ma = new MetadataAttribute()
                        {
                            AttributeType = oldMA.AttributeType,
                            Identifier = new MemberTypeContextIdentifier()
                            {
                                //entityId is coming from the target entity                               
  EntityId = retMd.Entities.First().Identifier,
                                //Id  is coming from the target entity
                                Id = retMd.Entities.First().Identifier.Id,
                                //internal Id  is coming from the target entity                             
    InternalId = retMd.Entities.First().Identifier.InternalId,
                                ModelId = newModelId,
                                MemberType = oldMA.Identifier.MemberType,
                                Name = oldMA.Identifier.Name
                            },
                            DataType = oldMA.DataType,
                            DataTypeInformation = oldMA.DataTypeInformation,
                            AuditInfo = oldMA.AuditInfo,
                            ChangeTrackingGroup = oldMA.ChangeTrackingGroup,
                            DisplayWidth = oldMA.DisplayWidth,
                            ExtensionData = oldMA.ExtensionData,

                            InputMaskId = oldMA.InputMaskId,
                            IsCode = oldMA.IsCode,
                            IsName = oldMA.IsName,
                            IsReadOnly = oldMA.IsReadOnly,
                            IsSystem = oldMA.IsSystem,
                            Permission = oldMA.Permission,
                            SortOrder = oldMA.SortOrder

                        };

                        //add all destination attributes to the metadata
                        newMD.Attributes.Add(ma);
                    }
                    //create the attributes metadata
                    c.MetadataCreate(new International(), newMD, true, out or);

                }
                //if operation is done and no error, displays message             
    if (or != null && or.Errors.Count == 0)
                    MessageBox.Show("DONE!");
            }
            catch (Exception ex)
            {
                //to displays errors if any             
    StringBuilder sb = new StringBuilder();
                if (or != null && or.Errors.Count > 0)
                {

                    foreach (Error err in or.Errors)
                    {
                        sb.AppendFormat("{0}" + Environment.NewLine, err.Code + " - " + err.Description);
                    }
                }

                if (sb.Length > 0)
                {
                    throw new Exception(sb.ToString());
                }
                else
                {
                    throw ex;
                }

            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

SQL2008 R2 Master Data Services Cumulative updates history and details

Hi,

UPDATE:
Here is a link to a great blog post from Jason Howell (Senior Escalation Engineer in the SQL Server Support team specializing in MDS)

http://blogs.msdn.com/b/mds/archive/2011/08/16/how-to-install-master-data-services-mds-service-pack-1-for-sql-server-2008-r2.aspx

___________________________________________________________________

here is a history of MDS cumulative updates / fixes

note : the latest cumulative update always contains all previous updates.
note 2:
here is another link for all SQL Server 2008 R2 builds that were released after SQL Server 2008 R2 was released : http://support.microsoft.com/kb/981356/en-us

_______________________________________________________________

MDS CU 2 http://support.microsoft.com/kb/2143880

This update fixes a number of issues related to the following areas in Microsoft SQL Server 2008 R2 Master Data Services. The following sections describe the fixes and functionality available after you apply this update.

Hierarchy Management

Collapse this tableExpand this table

Description
New members added to an entity in MDS while within a derived hierarchy will default the associated domain based attribute based on the user’s current location within the hierarchy.
In Explorer, the more option is available in the hierarchy tree for derived hierarchies.
Referential integrity is enforced for derived hierarchies with explicit caps.


Import and Export

Collapse this tableExpand this table

Description
The staging process supports the deletion of members from an entity that supplies domain-based attribute values for another entity.
In Integration Management, under Unbatched Staging Records, the Model and Version drop-down menus enable successful selection of a different model and version.
The staging process is enabled for the Metadata model.
System member records from the Metadata model cannot be deactivated by using the staging process.


Business Rules

Collapse this tableExpand this table

Description
Business rules can now be deployed by using the Model Deployment wizard or API even if there are staging errors for file attributes.
Users can add multiple Actions to a business rule without causing the error, “Failed to enable constraints.”
On the Edit Business Rule page, the contains the pattern condition and must contain the pattern action support up to 200 characters to allow for complex regular expressions.
On the Edit Business Rule page, users can use Delete from the right-click menu to delete a condition or an action without encountering the error, “An unknown error occurred.”
The Internet Information Services (IIS) application pool identity no longer needs sysadmin privileges for the SQL Server Database Engine instance or db_owner privileges to the Master Data Services database to successfully publish business rules. Previously, insufficient privileges for the application pool identity resulted in the error, “A database error has occurred. Contact your system administrator.”
Users can delete business rules that contain nested operators without specified conditions.

Attributes and Attribute Groups

Collapse this tableExpand this table

Description
In Explorer, when entering a value for a numeric attribute, users can specify very long numbers without encountering the conversion overflow error, “A general error occurred. System.OverflowException: Conversion overflows.”
In Explorer, when users edit numeric attribute values on the Member Information page, numbers following a decimal point are no longer rounded to two decimal places.
In Explorer, domain-based attribute values are retrieved from the database instead of from the cache. This enables new domain-based attributes values to be immediately available for an entity.
An attribute that belongs to more than one attribute group with different permissions now resolves as expected so that the least restrictive permission applies.
In System Administration, users can now reorder attribute groups without causing the attributes to disappear.


Versioning and Validation

Collapse this tableExpand this table

Description
When a user copies a version, the member ID is preserved so that records can be compared across versions even if the member’s code changes.
A new system setting, NotificationsPerEmail, has been added to specify the number of validation issues to include per e-mail when notifications are sent. This provides the ability to combine a number of validation issues in one e-mail rather than sending a separate e-mail for each validation issue.
Validation and copying versions is supported when two entities have references to one another (known as a recursive relationship).
In Version Management, on the Validate Version page, users can use the Model and Version drop-down menus to successfully select a different model and version for validation.
Validation issues are now properly removed after the issues have been fixed on the item edit page.
Validation issues have been improved to give more information about the issues found.

Users and Groups

Collapse this tableExpand this table

Description
In User and Group Permissions, on the Add groups page, users can add groups that contain a dash (-) in the group name.

User Interface Usability

Collapse this tableExpand this table

Description
Drag and drop functionality has been fixed throughout the application so that it works when Master Data Manager has been added as a Trusted Site in Internet Explorer.
The hierarchy pane has been fixed to work properly with the minimum supported resolution of 1024×768.

API

Collapse this tableExpand this table

Description
Deletion of a metadata type is limited to one type in a single API call.

 

___________________________________________________________________

CU8 : http://support.microsoft.com/kb/2534352 (10.50.1797.0)
no fix for master data services in SQL 2008 R2 cumulative update 8  :(

______________________________________________________________

CU7 : http://support.microsoft.com/kb/2507770 (10.50.1777.0)
2516439 FIX: “The script ‘/MDM/ScriptResource.axd’ contains multiple calls to Sys.Application.notifyScriptLoaded(). Only one is allowed” error on a SQL Server 2008 R2 MDS website

______________________________________________________________

CU6 : http://support.microsoft.com/kb/2489376 (10.50.1765.0)

2486113 : A drop-down list is always displayed instead of a search box when you double-click the value of the filter criteria box for an attribute in Entities Explorer of the SQL Server 2008 R2 MDS website

2497301 FIX: “Validate Version” page takes a long time to open or times out after you click “Validate version” on the SQL Server 2008 R2 MDS website

______________________________________________________________

CU5 http://support.microsoft.com/kb/2438347
no MDS update in it (as far I know)

______________________________________________________________

CU 4 : http://support.microsoft.com/kb/2345451 (10.50.1746.0)

2284503
FIX: You encounter two issues when you use Microsoft SQL Server 2008 R2 Master Data Services (MDS)

2410425
FIX: You receive an exception when you try to create an MDS database in SQL Server 2008 R2 MDS if a non-MDS database table is named “tblSystem”

2412136
FIX: The Entities Explorer grid displays few rows in a SQL Server 2008 R2 MDS website if you use a low screen resolution

______________________________________________________________

CU3 : http://support.microsoft.com/kb/2261464
no MDS update in it (as far I know)

______________________________________________________________

CU2 : http://support.microsoft.com/kb/2072493 (10.50.1720.0)

2143880
Bugs that are fixed in Microsoft SQL Server 2008 R2 Master Data Services June Update

______________________________________________________________

CU1 http://support.microsoft.com/kb/981355
no MDS update in it (as far I know)

Master Data Services : Getting Errors out of a ModelMembersBulkUpdate/Merge with API

In fact, you can get the error codes on MDS website : in “Integration Management/Staging Batches” clicking on the batch you want and clicking on button “view details for selected batch”
in order to do the same thing with API (get error codes), you’ll need to get info from the batch after it has been inserted. 


 

//get information related to a staging batch
 public Collection StagingGet(Collection stagingBatch, bool ReturnAllCriteria, bool ReturnMembers, bool ReturnAttributes, bool ReturnRelationShips, ref OperationResult or)
 {
 Collection colUnbatched = new Collection();
 Collection colBatches = new Collection();
 using (ServiceClient c = MDS_WSConnect.CreateMdsProxy())
 {
 or = new OperationResult();
 colBatches = c.StagingGet(new International(), true, new StagingResultCriteria() { All = ReturnAllCriteria, Attributes = ReturnAttributes, Members = ReturnMembers, Relationships = ReturnRelationShips },
 new StagingSearchCriteria() { StagingBatches = stagingBatch, StagingDataStatus= StagingDataStatus.All }, out or, out colUnbatched);
 List lstErr = new List();
//...do what you need with the error collection
foreach (StagingBatchError err in colBatches.First().Errors)
{
 lstErr.Add(err.ErrorCode + " - " + err.TargetCode);
 }
return colBatches;
}
}

so, complete process would be:

DateTime dtBefore = DateTime.Now; 
OperationResult or = new OperationResult();
  //filling new staging batch with entityMembers
  Collection colStaging = ModelMembersBulkMerge(colEntMembers);
  //initiating the staging process (not sure I really need that here in fact)
  Collection colBatches = StagingGet(colStaging, true, true, true, false, ref or);
  //triggering staging
  ProcessUnbatchedStaging(pModelId, pVersionId);
DateTime dtAfter = DateTime.Now;
TimeSpan ts = dtAfter.Subtract(dtBefore);

MessageBox.Show("members (bulk) inserted : " + colEntMembers.First().Members.Count() + "\r\n" + "time elapsed (seconds):" + ts.TotalSeconds.ToString());
//get back the batch to see if any errors

colBatches = StagingGet(colStaging, true, true, true, false, refor);

note: StagingDataStatus= StagingDataStatus.All –> get all including Errors

SQL 2008 R2 Master Data Services : Bulk Data Insert with API

In this article, I will talk about Master Data Services.
You can find the source code of this example on my MDS project on Codeplex:
http://mdsmanager.codeplex.com  

Special thanks to Suzanne Selhorn at Microsoft for help and support and her new great book about Master Data Services that you can find on Amazon :
http://www.amazon.com/Microsoft-Server-2008-Master-Services/dp/007175623X

Update 30 april 2011
a part of a answer message from Tyler Graham about synchronous /asynchronous operations:
 I wanted to ensure you understood that EntityMembersCreate and its partners calls are synchronous calls that will return any and all errors founds in the MDS load. (More so in Denali where some problems have been fixed)  ModelMembersBulkMerge and any calls with the ‘Bulk’ keyword leverage staging and will return success no matter what the disposition of the records as the use of staging is asynchronous.”


thanks to Tyler for this useful remark!

Note : 
__________________________________________________________________________________
EntityMembersCreate : only new member records with unique codes can be created with this operation. If a member code already exists, an error will be thrown in the returned error collection and the member will not be created or updated.

EntityMembersMerge : Many users have been confused by this operation and believe it has something to do with record survivorship or match merge functionality. This operation does nothing to look for possible matches or provide any survivorship functionality; it only allows users to create and update records simultaneously within MDS.
Information source : 
book: Master Data Services “Implementation and Administration” by Tyler Graham and Suzanne Selhorn
__________________________________________________________________________________
So, what’s the point:

you want to insert a big number of members in a MDS entity, with API (MDS WebService)
first solution :

Second Solution :

___________________________________________________________________
So let’s see the 2 solutions in details :

First solution  : (slow, not recommanded)
inserting each member with API method EntityMembersCreate

example:

private void btTest_Click(object sender, EventArgs e)
{
if (lstModels.SelectedItem != null && lstVersions.SelectedItem != null)
{
string pEntityName = (ucManageEntities1.lstEntities.SelectedItem as CustomEntity).Name;
string pModelName = (lstModels.SelectedItem as Identifier).Name;
string pVersionName = (lstVersions.SelectedItem as CustomVersion).Name;
List lst = new List();

for (int i = 1; i < = 4000; i++)
{
MemberIdentifier mi = new MemberIdentifier() { Code = "Code" + i.ToString(), Name = "Name" + i.ToString() };

Member m = new Member() { MemberId = mi };
m.Attributes = new Collection();
Identifier attId = new Identifier() { Name = "myTestAtt" };
m.Attributes.Add(new Common.ServiceReference1.Attribute() { Identifier = attId, Value = "AttValue" + i.ToString() });

CustomMember cm = new CustomMember(m);

lst.Add(cm);
}

EntityMemberCreate(pEntityName, pModelName, pVersionName, lst, true);
}
}

public EntityMembers EntityMemberCreate(string pEntityName, string pModelName, string pVersionName, List pMdmMembers, bool bCreate)
{

International international = new International();

EntityMembers entityMembers = new EntityMembers();
System.Collections.ObjectModel.Collection members = new System.Collections.ObjectModel.Collection();
entityMembers.Members = members;
entityMembers.EntityId = new Identifier() { Name = pEntityName };
entityMembers.ModelId = new Identifier() { Name = pModelName };
entityMembers.VersionId = new Identifier() { Name = pVersionName };
foreach (var mdmMember in pMdmMembers)
{

Member member = new Member();
MemberIdentifier memberIdentifier = new MemberIdentifier();
memberIdentifier.Code = mdmMember.Code;
memberIdentifier.MemberType = MemberType.Leaf;
memberIdentifier.Id = new Guid();
memberIdentifier.Name = mdmMember.Name;
member.MemberId = memberIdentifier;
member.Attributes = new System.Collections.ObjectModel.Collection();
foreach (var myAttribute in mdmMember.mbr.Attributes)
{
Common.ServiceReference1.Attribute attribute = new Common.ServiceReference1.Attribute();
attribute.Identifier = new Identifier() { Name = myAttribute.Identifier.Name };
attribute.Value = myAttribute.Value;
attribute.Type = AttributeValueType.String;
member.Attributes.Add(attribute);

}

members.Add(member);

}
if (bCreate)
{
using (ServiceClient c = MDS_WSConnect.CreateMdsProxy())
{
DateTime dtBefore = DateTime.Now;
OperationResult or = c.EntityMembersMerge(international, entityMembers);
DateTime dtAfter = DateTime.Now;
TimeSpan ts = dtAfter.Subtract(dtBefore);

MessageBox.Show("members merged : " + entityMembers.Members.Count() + "\r\n" + "time elapsed (seconds):" + ts.TotalSeconds.ToString());

}
}
return entityMembers;
}

Second Solution : with API method ModelMembersBulkMerge (fast, recommanded)
example:

 private void btTest2_Click(object sender, EventArgs e)
{
if (lstModels.SelectedItem != null && lstVersions.SelectedItem != null)
{
string pEntityName = (ucManageEntities1.lstEntities.SelectedItem as CustomEntity).Name;
Identifier pModelId = (lstModels.SelectedItem as Identifier);
string pModelName = (lstModels.SelectedItem as Identifier).Name;
Identifier pVersionId = (lstVersions.SelectedItem as CustomVersion).Identifier;
string pVersionName = (lstVersions.SelectedItem as CustomVersion).Name;
List<CustomMember> lst = new List<CustomMember>();

for (int i = 1; i <= 4000; i++)
{
MemberIdentifier mi = new MemberIdentifier() { Code = "Code" + i.ToString(), Name = "Name" + i.ToString() };

Member m = new Member() { MemberId = mi };
m.Attributes = new Collection<Common.ServiceReference1.Attribute>();
Identifier attId = new Identifier() { Name = "myTestAtt" };
m.Attributes.Add(new Common.ServiceReference1.Attribute() { Identifier = attId, Value = "myValue" + i.ToString() });

CustomMember cm = new CustomMember(m);

lst.Add(cm);
}
Collection<EntityMembers> colEntMembers = new Collection<EntityMembers>();
colEntMembers.Add(EntityMemberCreate(pEntityName, pModelName, pVersionName, lst, false));

DateTime dtBefore = DateTime.Now;

//filling new staging batch with entityMembers
Collection<Identifier> colStaging = ModelMembersBulkMerge(colEntMembers);
//initiating the staging process
Collection<StagingBatch> colBatches = StagingGet(colStaging, true, true, true, false);
//triggering staging
ProcessUnbatchedStaging(pModelId, pVersionId);

DateTime dtAfter = DateTime.Now;
TimeSpan ts = dtAfter.Subtract(dtBefore);

MessageBox.Show("members (bulk) inserted  : " + colEntMembers.First().Members.Count() + "\r\n" + "time elapsed (seconds):" + ts.TotalSeconds.ToString());

}

}
//triggering staging for a specific model and version
public void ProcessUnbatchedStaging(Identifier modelId, Identifier versionId)
{
using (ServiceClient c = MDS_WSConnect.CreateMdsProxy())
{
OperationResult or = new OperationResult();
c.StagingProcess(new International(), true, new StagingUnbatchedCriteria() { ModelId = modelId, VersionId = versionId }, out or);
}
}

//get information related to a staging batch
public Collection<StagingBatch> StagingGet(Collection<Identifier> stagingBatch, bool ReturnAllCriteria, bool ReturnMembers, bool ReturnAttributes, bool ReturnRelationShips)
{
Collection<StagingUnbatchedInformation> colUnbatched = new Collection<StagingUnbatchedInformation>();
Collection<StagingBatch> colBatches = new Collection<StagingBatch>();
using (ServiceClient c = MDS_WSConnect.CreateMdsProxy())
{
OperationResult or = new OperationResult();
colBatches = c.StagingGet(new International(), false, new StagingResultCriteria() { All = ReturnAllCriteria, Attributes = ReturnAttributes, Members = ReturnMembers, Relationships = ReturnRelationShips }, new StagingSearchCriteria() { StagingBatches = stagingBatch }, out or, out colUnbatched);

return colBatches;
}
}
public Collection<Identifier> ModelMembersBulkMerge(Collection<EntityMembers> modelMembers)
{

Collection<Identifier> colBatches = new Collection<Identifier>();
using (ServiceClient c = MDS_WSConnect.CreateMdsProxy())
{

OperationResult or = new OperationResult();
or = c.ModelMembersBulkMerge(new International(), modelMembers, out colBatches);

}
return colBatches;
}