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

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

  • Comments 8
  • Likes

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.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hello Travis,

    Following this post, we can now import the MP. Afterwards, when we try to open IR/CR or PR, SCSM console throws error "The specified enumaration value is not valid for the detailed information..."

    Is there sth else we're missing?

    Our Specs: We have extended the classes Problem, Incident and Change to include a new property Customers. The property is a List type.

    Thanks.

  • Can you please send your MP .xml file to scsmbeta [at] live [dot] com?

  • Hello Travis,

    I have the same problem. At attempt of creation of incident there is this error.

    Thanks.

  • @Lyubomir & Efarov -

    Thanks for pointing this out.  I was working on this with another customer and also discovered this.  I understand the problem better now and have updated the blog post.  Sorry for any confusion.

  • Hello Travis,

    It is necessary, that field value originally was empty and without filling of this field with value it would be impossible to save incident.

    Thanks.

  • Hello Travis,

    for SCSM 2012, should I use this solution too, or there is now an alternate better solution?

    Thanks

  • Omari - the situation is the same for SC 2012 and SC 2012 SP1.

  • Hello Travis,

    I created a new class with 4 list properties which I made mandatory in the CR form. I imported the MP with no issues, the required fields work and the workflow I created works as well. My problem is when I want to close, cancel, or put CR on hold I get the following error:

    Message: ChangeRequestStatusChangeTaskHandler has parameter that is not valid.

    Parameter name: node.DataTypeCCM_CustomCR

    System.ArgumentException: ChangeRequestStatusChangeTaskHandler has parameter that is not valid.

    Parameter name: node.DataTypeCCM_CustomCR

      at Microsoft.EnterpriseManagement.UI.SdkDataAccess.ConsoleTaskHandler.DoTask(IList`1 navigationNodes, NavigationModelNodeTask task, List`1 parameterList)

      at Microsoft.EnterpriseManagement.UI.SdkDataAccess.ConsoleTaskHandler.DoTask(IList`1 navigationNodes, NavigationModelNodeTask task)

      at Microsoft.EnterpriseManagement.ConsoleFramework.WindowJobRecord.ExecuteBackgroundJob(Object sender, ConsoleJobEventArgs eventargs)

      at Microsoft.EnterpriseManagement.ServiceManager.UI.Console.ConsoleJobExceptionHandler.ExecuteJob(IComponent component, EventHandler`1 job, Object sender, ConsoleJobEventArgs args)

    Any ideas?

    Thanks

    Julio B