User Tools

Site Tools

:: Version 2.6.0 ::

2_6_0:customization:uniqueness-rules

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

2_6_0:customization:uniqueness-rules [2019/08/20 18:07] (current)
vdumas created
Line 1: Line 1:
 +====== Prevent duplicates ======
 +
 +**Prerequisite**:​ You must be familiar with the [[latest:​customization:​insert-xml|wiki syntax]] and have already ​ [[latest:​customization:​add-attribute-sample|created an extension]].
 +
 +---- dataentry customization ----
 +learning ​     : Configure uniqueness rules
 +level_tag ​    : Beginner
 +domains_tags ​ : XML, Constrain, Dictionary
 +min version ​  : 2.1.0
 +----
 +
 +By customizing iTop, you can specify on a class, uniqueness rules, to **prevent duplicate entries**. \\
 +In this Tutorial we will see:
 +  * How uniqueness rules behave from a user perspective
 +  * How to define new uniqueness rules
 +  * Uniqueness rules defined on Person class in iTop out of the box
 +  * Removing an existing uniqueness rule
 +
 +===== Behavior =====
 +
 +  * A rule would specify the scope of objects on which the uniqueness must be checked. For example, you don't want to have two persons with the same employee number, unless that number is empty. The scope would then be every Person with ''​employee_number''​ not empty. ​
 +  * During a single creation or modification made on the console or the portal, a rule can either ​
 +    * block the creation/​update of the object
 +{{ :​latest:​release:​uniqueness-error.png?​nolink&​600 |}}
 +    * or just display a warning message after the creation/​update.
 +{{ :​latest:​release:​uniqueness-warning.png?​nolink&​400 |}}
 +  * A uniqueness rule applies on one or multiple fields of the class (including ExternalFields)
 +  * Uniqueness on attribute types such as File, Image, Dashboard, Stopwatch,​... are not supported (//​incomplete list//).
 +
 +<note tip>If you want a Uniqueness Rule for a Person on ''​Organization''​ and ''​Employee number'',​ but this rule only applies to your company, then you define the scope of the rule to be "Only Persons of organization XXX"</​note>​
 +
 +===== Default rules =====
 +
 +<​note>​In Standard Data Model, we have added those rules:
 +  * Class Brand, id=''​name'',​ field ''​name''​ **must** be unique.
 +  * Class Model, id=''​name_brand'',​ fields: ''​name + brand_id''​ **must** be unique.
 +  * Class Person, id=''​employee_number''​ fields: ''​org_id + employee_number''​ **must** be unique only **if** employee_id is defined.
 +  * Class Person, id=''​name'',​ fields: ''​org_id + first_name + name''​ **should** be unique (//warning only//).
 +</​note>​
 +
 +====== Defining your own rule ======
 +
 +For defining Uniqueness rules we only need to write XML.
 +
 +===== Unique name within sub-classes =====
 +
 +In this usecase we want to prevent any FunctionalCI to have the same name as another FunctionalCI **only** if they both belong to the same sub-class. For example a NetworkDevice and a Server can have the same name, but two Servers must not have the same name.
 +
 +<code XML itop-design / classes / class@FunctionalCI / properties>​
 +        <​uniqueness_rules>​
 +          <rule id="​functionalci_name"​ _delta="​define">​
 +            <!-- field or combination of "​FunctionalCI"​ fields which must be unique -->
 +            <​attributes>​
 +              <​attribute id="​name"/>​
 +              <​attribute id="​finalclass"/>​
 +            </​attributes>​
 +          <!-- ... -->
 +</​code>​
 +
 +<code XML itop-design / dictionaries / dictionary@EN US / entries>
 +<entry id="​Class:​FunctionalCI/​UniquenessRule:​functionalci_name">​
 +  <​![CDATA[there is already a '​$this->​finalclass$'​ with the same name]]>
 +</​entry>​
 +</​code>​
 +
 +<​note>​Note the use of the placeholder **<​nowiki>'​$this->​finalclass$'</​nowiki>​** within the error message</​note>​
 +
 +This could also have been done as separate uniqueness rule on each an every sub-class, but that's more work.
 +
 +FYI: ''​finalclass''​ is a magic attribute which only exist on classes which are abstract or have a parent other than ''​cmdbAbstractObject''​ or ''​DBObject''​.
 +
 +===== Unique name across sub-classes ====
 +
 +In this use case we want to prevent two FunctionalCIs to have the same name. Except if the FunctionalCI is in fact a SoftwareInstance,​ a MiddlewareInstance,​ a DatabaseSchema or an ApplicationSolution,​ in which case, we don't care. 
 +
 +Let's assume we have just two FunctionalCI in our iTop:
 +  * a NetworkDevice named "​test.combodo.com" ​
 +  * and a ApplicationSolution named "​iTop"​
 +What we can and cannot do:
 +  * This rule will prevent creation of a Server named "​test.combodo.com"​ //as a NetworkDevice exists already with that same name//
 +  * It will prevent the rename of a Server into "​test.combodo.com"​ //as a NetworkDevice exists already with that same name//
 +  * It will allow creation of a Server named "​iTop"​ //as the existing ApplicationSolution named "​iTop"​ is part of the final classes which are filtered out//
 +
 +<code XML itop-design>​
 +  <​classes>​
 +    <class id="​FunctionalCI"​ _delta="​must_exist">​
 +      <​properties>​
 +        <​uniqueness_rules>​
 +          <!-- For the "​id"​ it must be a single word without special character but underscore -->
 +          <rule id="​functionalci_name"​ _delta="​define">​
 +            <!-- field or combination of "​FunctionalCI"​ fields which must be unique -->
 +            <​attributes>​
 +              <​attribute id="​name"/>​
 +            </​attributes>​
 +            <!-- Define an OQL WHERE clause with condition on FunctionalCI fields -->
 +            <!-- It will be combined this way "​SELECT FunctionalCI WHERE " + <​filter>​ -->
 +            <​filter><​![CDATA[
 +               ​finalclass NOT IN ('​DBServer','​Middleware',​
 +              '​OtherSoftware','​WebServer','​PCSoftware','​MiddlewareInstance',​
 +              '​DatabaseSchema','​ApplicationSolution'​)]]>​
 +            </​filter>​
 +            <!-- This flag allow you to keep the rule in the XML but desactivate it -->
 +            <​disabled>​false</​disabled>​
 +            <!-- If true or ommitted, a duplicate is blocking the creation/​update -->
 +            <!-- otherwise it displays a warning message after creation/​update -->
 +            <​is_blocking>​true</​is_blocking>​
 +          </​rule>​
 +        </​uniqueness_rules>​
 +      </​properties>​
 +    </​class>​
 +  </​classes>​
 +  <​dictionaries>​
 +    <​dictionary id="EN US" _delta="​must_exist">​
 +      <​entries>​
 +        <entry id="​Class:​FunctionalCI/​UniquenessRule:​functionalci_name"​ _delta="​define">​
 +          <​![CDATA[There are already a Functional CI with that name, please use another name.]]>
 +        </​entry>​
 +        <entry id="​Class:​FunctionalCI/​UniquenessRule:​functionalci_name+"​ _delta="​define">​
 +          <​![CDATA[FunctionalCI name should be unique]]>​
 +        </​entry>​
 +      </​entries>​
 +    </​dictionary>​
 +  </​dictionaries>​
 +</​code>​
 +
 +<​note>​Note the syntax of a dictionary entry **"​Class:"​ + //​class-name//​ + "/​UniquenessRule:"​ + //​rule_id//​**</​note>​
 +  * This entry is used for the error message related to the Uniqueness rule. \\
 +  * The same code with a + at the end, correspond to a description of the Uniqueness rule, not yet displayed anywhere, but probably one day, it will be displayed in the Datamodel viewer.
 +
 +
 +===== Existing Rules on Person =====
 +
 +Let's look at the existing uniqueness rules on Person, provided by default in iTop. There are 2 rules:
 +
 +__employee_number__
 +  * It's a blocking rule, it will prevent creation/​update in case of error
 +  * It will prevent two persons belonging to the same organization to have the same employee number, ​
 +  * An empty employee number is allowed and will not generate an error, even if other persons exist with an empty employee number in the same organization.
 +  * Two persons can have the same non-empty employee number only if they belongs to two different organizations.
 +__name__
 +  * This rule is just a warning, it does not prevent creation/​update,​ it just display a message.
 +  * It is generated if there is an homonym within the same organization
 +
 +Here is how they have been defined:
 +
 +<code XML itop-design / classes / class@Person / properties>​
 +   <​uniqueness_rules>​
 +      <rule id="​employee_number">​
 +         <​attributes>​
 +            <​attribute id="​org_id"/>​
 +            <​attribute id="​employee_number"/>​
 +         </​attributes>​
 +         <​!-- Empty employee_number is allowed and will not be treated as a duplicate -->
 +         <​filter><​![CDATA[employee_number != ''​]]></​filter>​
 +         <​disabled>​false</​disabled>​
 +         <​is_blocking>​true</​is_blocking>​
 +       </​rule>​
 +       <​rule id="​name">​
 +          <​attributes>​
 +             <​attribute id="​org_id"/>​
 +             <​attribute id="​name"/>​
 +             <​attribute id="​first_name"/>​
 +          </​attributes>​
 +          <​filter/>​
 +          <​disabled>​false</​disabled>​
 +          <​is_blocking>​false</​is_blocking>​
 +       </​rule>​
 +     </​rules>​
 +   </​uniqueness_rules>​
 +</​code>​
 +
 +===== Removing a Rule =====
 +
 +In this example we will remove an existing uniqueness rule, which is in the default iTop datamodel.
 +In order to remove a uniqueness rule, you need to know two things:
 +  * on which class it has been declared, here "​Person"​
 +  * and its ''​rule_id''​ here ''​employee_number
 +
 +Removing a rule requires a piece of XML embedded in an extension, just like adding a rule. The important piece here is **_delta="​delete"​** within the upper node which must be removed with all its sub-nodes
 +
 +<code XML itop-design / classes>
 +    <class id="​Person"​ _delta="​must_exist">​
 +      <​properties>​
 +        <​uniqueness_rules>​
 +          <rule id="​employee_number"​ _delta="​delete"/>​
 +        </​uniqueness_rules>​
 +        </​properties>​
 +      </​class>​
 +</​code>​
 +
 +
 +===== Partially disabling a rule =====
 +
 +In this usecase we suppose that this rule was defined on FunctionalCI:​
 +
 +<code XML classes / class@FunctionalCI / properties>​
 +        <​uniqueness_rules>​
 +          <rule id="​functionalci_name"​ _delta="​define">​
 +            <!-- field or combination of "​FunctionalCI"​ fields which must be unique -->
 +            <​attributes>​
 +              <​attribute id="​name"/>​
 +              <​attribute id="​finalclass"/>​
 +            </​attributes>​
 +          <!-- ... -->
 +</​code>​
 +
 +and we want to change it for DatacenterDevice (//which is a child class of FunctionalCI//​),​ for which we want a different behavior with a uniqueness of name across all sub-classes of DatacenterDevice.
 +
 +For this we disable the parent class rule "​functionalci_name"​ and define a new rule, here "​datacenterdevice_name"​.
 +
 +<code XML classes / class@DatacenterDevice / properties>​
 +        <​uniqueness_rules>​
 +          <!-- here we use the same rule_id as the rule we want to stop -->
 +          <!-- We are on a child class, so the node is new, which explain the _delta="​define"​ -->
 +          <rule id="​functionalci_name"​ _delta="​define">​
 +            <!-- '​disabled'​ is the only tag supported when overwriting an existing rule_id -->
 +            <!-- It disables the '​functionalci_name'​ rule that for DatacenterDevices -->
 +            <​disabled>​true</​disabled>​
 +          </​rule>​
 +          <!-- then we can add another rule or not... --> ​                   ​
 +          <rule id="​datacenterdevice_name"​ _delta="​define">​
 +            <​attributes>​
 +              <​attribute id="​name"/>​
 +            </​attributes>​
 +          <!-- ... -->
 +</​code>​
 +
 +<note warning>​A rule id must be unique within each branch of the class hierarchy! \\
 +Reusing one within a branch is only allowed to disable the parent rule</​note>​
 +
  
2_6_0/customization/uniqueness-rules.txt ยท Last modified: 2019/08/20 18:07 by vdumas

";