Why Won’t My MP Import? The Case of the Required Property Without a Default Value

This situation has come up a couple of times now so it seems worth of a blog post.  Here’s the situation – a customer is using the SCSM Authoring Tool to extend a class and add a new property.  The customer marks the value as required because the user’s should enter a value for the property each time and object of that class is created.  Now the customer tries to import the MP and get’s this error message:

image

“The value specified for DefaultValue is not valid.”  What does that mean?  The customer didn’t even specify a Default Value!  Why would the customer specify a Default Value when the purpose of making the property Required is because the customer wants the user to choose a value each time?  Sometimes a default value might make sense, but lots of times it won’t so why is a Default Value mandatory if the customer makes the property Required?

Here’s the reason:

Consider that essentially for each class there is a corresponding database table.  Each property defined on the class is essentially a column on that table.   The data type of the property defined in the MP defines the data type of the column in the table.  If you define things like max value, min value, max length, min length, etc. on the property those are reflected as additional constraints on the column in the table.

In this case if you say that a property is Required, that is the equivalent of making the column in the table be Nullable=False (means that every row in the table must have a value for that column).

If you were to import this MP into a SCSM system that had no data in the table this would probably work (I haven’t tested it).  If you import it into a SCSM system that already has data in the table (and you don’t specify a default value) you will get this error because SQL doesn’t know what value to put into the new non-nullable column for each of the existing rows!  If you provide a DefaultValue for that property in the MP then you can import the MP and it will set the value for that column for all existing rows to the default value.

In this particular case the customer raised the situation is a little more interesting because the data type of the property was enum/list data type.  That means that the default value must point to the ID of an enum/list item.  When you create a new enum/list data type property in the authoring tool, behind the scenes it creates the “root” node of the enum hierarchy (since lists can be hierarchical).  This enum is called ‘TestList’ in my example below.  While you can technically set the DefaultValue to be equal to that new EnumerationValue and it will import you won’t be able to create new objects of the class because the list item picker on the form doesn’t let you select the root node in the enum hierarchy.  Therefore you need to set the DefaultValue of the property to be a non-root EnumerationValue in the hierarchy.  Unfortunately right now we don’t allow you to create lists in the authoring tool so we are in a catch 22 situation.  You’ll need to do the following:

1) Set the Required attribute on the property = the same name as the root enum for now

image

2) Then save the MP in the authoring tool.

3) Then open the MP in an XML editor and do the following:

a) Create a new enumeration value element under the current one (see below example called ‘TestList.Default’.  Set the parent of that enumeration value to the root enumeration value (in this case ‘TestList’

b) Set the DefaultValue to be equal to the new EnumerationValue you just created.

c) Don’t forget to add a Display String element (for each language pack if you are using more than one language) for the default enumeration value.

In MP XML it would look like this:

    <EntityTypes>
      <ClassTypes>
        <ClassType ID="ClassExtension_544dcd7b_f44b_4cbf_9310_c7d27377beb9" Extension="true">
          <Property ID="CustomExtension" Type="enum" Key="false" Required="true" EnumType="TestList" DefaultValue="TestList.Default" />
        </ClassType>
      </ClassTypes>
      <EnumerationTypes>
         <EnumerationValue ID="TestList" Accessibility="Public" />
	<EnumerationValue ID="TestList.Default" Accessibility="Public" Parent="TestList" />
      </EnumerationTypes>
    </EntityTypes>
<LanguagePacks>    
  <LanguagePack ID="ENU" IsDefault="true">
     <DisplayStrings>
...
        <DisplayString ElementID="TestList.Default">
           <Name>Default Value</Name>
        </DisplayString>
...

 

Now you can import the MP.  The value of this property for all existing objects will be set to the default value on MP import.  Remember they have to be set to something because this is a non-nullable field.  If you open the form the list picker will by default set this property equal to the default value.

I realize that there may be a case where you want to not set a default value and make it required so that the user is required to enter or select a value.  Unfortunately, that isn’t possible with the current design.  I’ve filed a DCR (193591) to see if we can enable doing this kind of extension when there are no existing objects in the table.  Until/unless that DCR is implemented this is the behavior.

Just as a footnote on this blog post:  This is also true of when you are upgrading a class from one version to another.  You can’t add required properties without a default value.  You can however have a new class that has a required property without a default value because we are creating a new table in that scenario and therefore can create a non-nullable column no problem.