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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 :
1
2
3
4
5
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

1
2
XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(BRAttributeValueArgument),typeof(BRBlankArgument)
                                                                         ,typeof(BRDomainBasedAttributeArgument)});
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
              // 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 :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  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:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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;
           }
       }
Tagged , , , , , , , , , . Bookmark the permalink.

About Xavier

7 years+ .net consulting

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

  1. Miron says:

    Posted a few weeks ago some methods that could help.

    In my experience attempt to save a business rule with all properties and collections failed. I had to create business rule, could think of it as header. This is how you would create business rule in UI, too. And than add one section at a time actions and conditions. I have also added an initial call to get all entities interested in, cache those and lookup in collection using link, which speeds up creating business rules quite a bit. Please let me know how I can contact you, if you are interested. Thank you, Miron.

  2. Scott Pedersen says:

    Great work, this will come in very useful for business rule changes that need to be migrated between environments.

Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha * Time limit is exhausted. Please reload CAPTCHA.