CRM 4.0 Master Schema Management and Customization Change Control

 Recently I found a CRM 4.0 Schema comparison tool that I find makes life much easier when I’m playing the role of Schema Master.  Managing schema changes is in my opinion a arduous and very manual process.  It is  not advisable to use TFS for schema file comparisons and definitely not for merging, this is because TFS does line by line comparison not XML tag comparisons.  The Customization Comparison Utility lets you compare the customization files between two Microsoft Dynamics CRM systems and the Configuration Data Utility lets you transfer custom configuration data from one Microsoft Dynamics CRM system to another.   You can download the solution file here

The process I recommend for the proper management and change control practices   essential for the ongoing life cycle of a Microsoft CRM Dynamics Organization Database Schema.  The diagram below represents the three typical scenarios that the Schema Master may encounter on a frequent basis.  The three scenarios are Jr. Developer or Third Party Developer interactions, Senior Developer Interactions and Multi-Developer Entity Edits.  Using the Customization Comparison Utility along with this process will ensure the integrity of your CRM schema and save you from a lot of pain.

  

Master Schema Scenarios

Scenario 1

Under scenario 1 a junior developer or a third-party or outside vendor may need to promote changes to the CRM Master Schema.  In this circumstance the Schema Master would likely be responsible for heavy validation of the schema changes.

1.       The schema items impacted are exported from the developers environment .

2.       The schema items impacted are documented in a standard SharePoint change-log.

3.       The schema export file is checked in to the weekly schema build folder.

4.       The Schema Master reviews the change-log and the may make manual or automated adjustments to the Master Schema.

Scenario 2

Under scenario 2 a senior developer may need to promote changes to the CRM Master Schema in this circumstance would likely be responsible for validation of the schema changes.

1.       The schema items impacted are exported from the developers environment .

2.       The schema items impacted are documented in a standard SharePoint change-log.

3.       The schema export file is checked in to the weekly schema build folder.

4.       The Schema Master reviews the  change-log and the may make manual or automated adjustments to the Master Schema.

Scenario 3

Under scenario 3 multiple developers may need to promote changes to the CRM Master Schema impacting the same entity.  In this circumstance the developers would likely be responsible for creating and validating a single schema export file.

1.       The schema items impacted are exported from the developers environment .

2.       The schema items impacted are documented in a standard SharePoint change-log.

3.       The schema export file is checked in to the weekly schema build folder.

4.       The Schema Master notifies the developers of potential conflicts or collisions.

5.       The developers create a single schema export file and check it in to TFS.

6.       The Schema Master reviews the change-log and the may make manual or automated adjustments to the Master Schema.

The TFS Role

TFS is used as a repository for the incremental schema edits that are proposed as candidates to the Schema-Master.  It’s critical that developers only submit specific entity schema segments rather than the full CRM schema, this is because TFS analyzes code line by line rather than in the XML  tag format the CRM schema model uses.  Also because the environment that the CRM schema is exported from can alter the format and order of the XML.  For these reasons it will be incumbent upon the Schema-Master to understand where the schema segments are coming from and to identify the risks associated with the submitting party.

The SharePoint Role

A standard SharePoint form should be used to capture the schema changes being submitted by each developer.  The SharePoint form should capture at minimum:

               

o    ID Number

o    Entity, Workflow or Role Name

o    Attribute

o    Deployment Comments

o    Impact Analysis Comments

The ID Number shoul

 

d always be references within the TFS check-in comments   and included in the release and deploy notes sent to the Deployment team for each build.

 

 

 

 

 
 
 
 
 
 
 
Advertisements

Attaching Javascript code to a CRM Toolbar Button

Attaching Javascript code to a tool bar button can be very ugly.  Generally the code needs to be included within the CRM, ISV Config  XML file.  It’s pretty easy to add a button via the ISV Config.  Click Here for more information on adding custom buttons to a Microsoft Dynamics CRM Entity form, toolbar.

The red highlighted Javascript tag below shows you where you would typically place your JavaScript or JavaScript function call but this isn’t the best place for the JavaScript.  I have seen huge JavaScript routines embedded in to the tag whci makes debugging and readability a painful exercise.  Even if you call a JavaScript function and leave the tag nice and cleas as shown here that Javascript function has to be maintained outside of the CRM Model.

<Entities>
        <Entity name=”new_customentity”>
          <ToolBar ValidForCreate=”0″ ValidForUpdate=”1″>
            <ToolBarSpacer></ToolBarSpacer>
            <Button Icon=”/_imgs/ico_18_debug.gif” JavaScript=”
DuplicateRecord (10016);”>
              <Titles>
                <Title LCID=”1033″ Text=”Duplicate Record” />
              </Titles>
              <ToolTips>
                <ToolTip LCID=”1033″ Text=”Copies a record based on this open record.” />
              </ToolTips>
            </Button>
            <ToolBarSpacer />
          </ToolBar>
        </Entity>
      </Entities>
 

The solution is pretty simple.

If we change the structure of our JavaScript function a bit we can simply place it in a Entity’s form OnLoad Event.  The key syntax is simply  MyFunction = function() .

Here is a working example of a function I wrote which calls a web service to copy the  current open record and create a new one based on it,

The CRM Form OnLoad Event JavaScript

DuplicateRecord = function() {

    try {
        var oXmlHTTP = new ActiveXObject(“Msxml2.XMLHTTP”);
       oXmlHTTP.Open(“POST”, “/somepath/ DuplicateRecord Service.asmx/ DuplicateRecord?mso-spacerun: yes”>      + crmForm.ObjectId, false);
        oXmlHTTP.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”)
        oXmlHTTP.Send(‘jobId=’ + crmForm.ObjectId);
        var newId = oXmlHTTP.responseXML.selectSingleNode(“string”).text;
   }
    catch (e) {
        debugger;
        return null;
    }
}

 

The ISV Config  XML Tag

<Button Icon=”” Url=”” PassParams=”1″ WinParams=”” WinMode=”0″ JavaScript=” DuplicateRecord ();”>
              <Titles>
                <Title LCID=”1033″ Text=” Duplicate This Record ” />
              </Titles>
              <ToolTips>
                <ToolTip LCID=”1033″ Text=”Copy Record” />
              </ToolTips>
            </Button>
 

Conclusion

I like this approach because now all our JavaScript is still maintained within the CRM Entity’s and for a number of good reasons that’s where a Microsoft Dynamics CRM  application should store the JavaScript.  Because its with the entity it will get exported with your model and other customizations.

Working With CRM 4.0 Data Types and Form Controls

Boolean

Specifies a field  that displays one check box or two radio buttons. The Boolean field type is one display option for bit type attributes. The other option is list. The list option uses the Picklist field type.

Note   Changing the formatting options of a bit attribute is done on the form, not in the attribute definition like other attributes. Changing the formatting option from a check box or two radio buttons to a list will change the way that you access the values in the form, potentially breaking your code.

The following properties are available:

Boolean properties Type Description
{Field}.DataValue Boolean or Null Get/set property. The original value is left unchanged if the new value cannot be parsed.
{Field}.DefaultValue Boolean Get property. Returns the default value for the field.

 

Example

The following code example shows how to set a field of type Boolean.

crmForm.all.SOME_BOOLEAN_FIELD_ID.DataValue = true;
 
crmForm.all.SOME_BOOLEAN_FIELD_ID.DataValue = false; 

 

Customer

A Customer field represents a type of Lookup where either an account or contact is a valid type of record.

The following properties are available:

Customer or Regarding properties Type Description
{Field}.DataValue   Specifies an array of lookup objects. For the Customer field this array always has a length of one. DataValue is Null when no value is selected. Set DataValue to Null to make the lookup field blank.

 

Example

The following code example shows how to use a Customer field type.

var customer = new Array();
customer = null;

// This gets the lookup for the attribute customerid on the Opportunity form.
customer = crmForm.all.customerid.DataValue;

// If there is data in the field, show it in a series of alerts.
if (customer[0] != null)
{
   // The name of the customer.
   alert(customer[0].name);

   // The GUID of the customer.
   alert(customer [0].id);

   // The entity type name of the customer.
   alert(customer[0].typename);
}

 

DateTime

A DateTime field can be formatted to show both the date and time, or the date only. The following properties are available:

DateTime properties Type Description
{Field}.DataValue Date or Null Get/set property.The original value is left unchanged if the new value cannot be parsed.
{Field}.TimeVisible Boolean Get property.This property specifies if the time is to be shown.

 

Example

The following code example shows how to use a field of type DateTime.

var oDate;
var oToday;

oDate =  crmForm.all.scheduledend.DataValue;
if (oDate == null) {
    oDate = new Date();
}

oToday = new Date();
oDate = oToday;
oDate = oDate.setHours(17,0,0);

if (oDate.TimeVisible)
{
   alert("The time is visible.");
}
else
{
   alert("Only the date is visible; the time is hidden.");
}

crmForm.all.scheduledend.DataValue = oDate;

 

Duration

Duration fields are presented as a picklist giving the user a selection of time options from 1 minute to 3 days. But the actual value of a duration field is an integer. If a user types an integer into the field or your code sets the value of the integer representing minutes, the field will convert that value into a more user-friendly unit of measurement. For example, 420 will be displayed as 7 hours.

The following properties are available:

Duration properties Type Description
{Field}.DataValue integer or Null Get/set property.The duration can be set to Null. The original value is left unchanged if the new value cannot be parsed.

 

Example

The following code example shows how to use a field of type Duration.

var iMinutes = 60; crmForm.all.SOME_DURATION_FIELD_ID.DataValue = iMinutes;
 
 
 

E-mail Body

This field type appears in the E-mail activity form. The following properties are available:

E-mail body field methods Type Description
{Field}.DataValue String Used to get the HTML stream for the e-mail body.

Remarks

The HTML stream that defines the DataValue for an e-mail body field is read-only. The DataValue is not available to be read in the OnLoad event.

Example

The following code example shows how to use a field of type E-mail body.

var oField = crmForm.all.SOME_EMAILBODY_FIELD_ID;

alert(The field's HTML is: " + oField.DataValue);

 

 

Float

The following properties are available:

Float properties Type Description
{Field}.DataValue float or Null Get/set property. The original value is left unchanged if the new value cannot be parsed.
{Field}.Min Integer Get property. Returns the minimum allowed value.
{Field}.Max Integer Get property. Returns the maximum allowed value.
{Field}.Precision Integer Get property. Returns the number of digits allowed. This is a value between 0 and 5.

 

Example

The following code example shows how to use a field of type Float.

var oField = crmForm.all.SOME_FLOAT_FIELD_ID;

var iValue = 1976.1102;

// Set the precision of the value.
var oNumber = new Number(iValue);
iValue = oNumber.toPrecision(oField.Precision);

if (iValue < oField.Min)
{
   iValue = oField.Min;
}
else if (iResponse > oField.Max)
{
   iValue = oField.Max;
}

oField.DataValue = iValue;

 

Integer

The following properties are available:

Integer properties Type Description
{Field}.DataValue Integer or Null Get/set property. The original value is left unchanged if the new value cannot be parsed.
{Field}.Min Integer Get property. The minimum allowed value.
{Field}.Max Integer Get property. The maximum allowed value.

 

Example

The following code example shows how to use a field of type Integer.

var oField = crmForm.all.SOME_INTEGER_FIELD_ID;

var iValue = 1000;

if (iValue < oField.Min)
{
   iValue = oField.Min;
}
else if (iValue > oField.Max)
{
   iValue = oField.Max;
}

oField.DataValue = iValue;
 
 

Lookup

A Lookup field type represents the relationship attribute on the related entity. The valid type for the lookup is established in the relationship. Although Lookup is frequently used as a generic term, there are different types of lookups and technically Lookup is the most restrictive kind of field type. Unlike Customer or Regarding, only one entity type is valid in a lookup. Unlike PartyList, only one reference is stored in the field. A lookup field is defined by using the following attributes:

Attribute Type Description
id String The GUID of the item. Required for set.
type Integer Deprecated. The object type code.
typename String The entity name of the item. Required for set.
name String The name of the item to be displayed. Required for set.
data   Any other data. Optional for set.

The following properties are available:

Lookup properties Type Description
{Field}.DataValue An array of lookup objects Get/set property.For lookups this must be an array with the length of one. DataValue is Null when no value is selected. Set DataValue to Null to make the lookup field blank.

Example

The following code example shows how to read values from a field of type Lookup.

var lookupItem = new Array;

// This gets the lookup for the attribute primarycontactid on the Account form.
lookupItem = crmForm.all.primarycontactid.DataValue;

// If there is data in the field, show it in a series of alerts.
if (lookupItem[0] != null)
{
   // The text value of the lookup.
   alert(lookupItem[0].name);

   // The GUID of the lookup.
   alert(lookupItem[0].id);

   // The entity type name.
   alert(lookupItem[0].typename);

}

Example

The following code example shows how to set values in a field of type Lookup. This example shows how to set the parent account lookup field on the account form.

//Create an array to set as the DataValue for the lookup control.
var lookupData = new Array();
//Create an Object add to the array.
   var lookupItem= new Object();
//Set the id, typename, and name properties to the object.
   lookupItem.id = '{1AAC1363-01A1-DB11-8432-0003FF9CE217}';
   lookupItem.typename = 'account';
   lookupItem.name = 'A Bike Store';
// Add the object to the array.
   lookupData[0] = lookupItem;
// Set the value of the lookup field to the value of the array.
   crmForm.all.parentaccountid.DataValue = lookupData;

Memo

Memo represents a multiline text box using the ntext attribute type. The following properties are available:

Memo properties Type Description
{Field}.DataValue A reference to a string object Get/set property.
{Field}.MaxLength Integer Get property.The maximum length of the string.

 

Example

This field is used in the same manner as a String Type.

 
 

Owner

A Owner field represents a Lookup where the linked record can be any record type that can be presented in the field.

The following properties are available:

Regarding properties Type Description
{Field}.DataValue   For the regarding field type this is an array with a length of one. DataValue is Null when no value is selected. Set DataValue to Null to make the lookup field blank.

Example

The following code example shows how to use a field of type Owner.

var lookupItem = new Array;
lookupItem = null;

// This gets the lookup for the attribute regardingobjectid on the Task form.
lookupItem = crmForm.all.ownerid.DataValue;

// If there is data in the field, show it in a series of alerts.
if (lookupItem[0] != null)
{
   // The text value of the lookup.
   alert(lookupItem[0].name);

   // The GUID of the lookup.
   alert(lookupItem[0].id);

   // The entity type name.
   alert(lookupItem[0].typename);
}

PartyList

A type of Lookup that allows for multiple references to records of multiple types of entities to be set in a single field. A PartyList is typically found on e-mail activities to represent the To, Bcc and cc fields. A PartyList is defined by using the following attributes:

Attribute Type Description
id String The GUID of the item. Required for set.
type Integer Deprecated. The object type code.
typename String The entity name of the item. Required for set.
name String The name of the item to be displayed. Required for set.
data   Any other data. Optional for set.

 

The following properties are available:

PartyList properties Type Description
{Field}.DataValue An array of lookup objects Get/set property.For PartyLists this must be an array with the length of at least one. DataValue is Null when no value is selected. Set DataValue to Null to make the lookup field blank.
 
 

Picklist

A picklist contains several options. Each option has the following attributes:

Attribute Description
DataValue The index value of the selected option.
Text The text of the picklist option.

The following properties and methods are available:

Picklist properties and methods Type Description
{Field}.DataValue string Get/set propertyGet returns a string representation of the value of the selected option. You can use the method parseInt() to safely convert this to an integer value.

Set changes the selection to the value specified.

{Field}.SelectedText string Get propertyReturns the string value of the selected option.
{Field}.GetSelectedOption option Picklist optionReturns a Picklist option.
{Field}.Options array of picklist options Get/set propertyGet returns an array of Picklist option objects.

Set defines a new set of options, specified by an array of Picklist option objects.

{Field}.AddOption(Text, DataValue) option Used to add an option to the end of the current control’s collection.Text – a string value to be displayed in the option.

DataValue – an integer value that represents the index of the option.

Text and DataValue cannot be Null.

Data is used for storing arbitrary data on the picklist object.

To define valid options, you must modify the Attribute definition by using the Customization tools or the metadata APIs. You should not create new picklist options programmatically in form event code. Manipulating the Options array is the most common solution to ensure valid picklist data.

{Field}.DeleteOption(value) integer Used to delete the option specified by value from the control’s option collection. Does nothing if the option does not exist.
{Field}.DefaultValue integer Get/set property.Get returns the default value for the picklist.

Set specifies the default value for the picklist.

Remarks

All the valid picklist options are defined in the Microsoft Dynamics CRM Metadata. When a record is saved with an invalid picklist option selected the field will be set to the default value and the invalid data will be lost.

There are two supported methods for retrieving the current selection for a picklist field as shown here.

The following returns the text value of the selected picklist item.

crmForm.all.(picklistitem).SelectedText

The following returns the index of the selected picklist item.

crmForm.all.(picklistitem).DataValue

Example

The following code example shows how to use a field of type Picklist. Note that when you add an option to a Picklist, the option must already exist in the set of possible options.

var oField = crmForm.all.SOME_PICKLIST_FIELD_ID;

// Capture the fourth option
var oOption = oField.Options[4];

// Show how many options are available
alert("Original length :"+ oField.Options.length);

// Set the field to the first option by value
oField.DataValue = 1;

// Show the text for the first option
alert(oField.SelectedText);

// Remove the fourth option
oField.DeleteOption(4);

// show the new length
alert("New length :"+ oField.Options.length);

// Restore the fourth option
oField.AddOption(oOption.Text, oOption.DataValue);

// Show the restored length
alert("Restored length :"+ oField.Options.length); 
 

Regarding

A Regarding field represents a Lookup where the linked record can be any record type that can be presented in the field.

The following properties are available:

Regarding properties Type Description
{Field}.DataValue   For the regarding field type this is an array with a length of one. DataValue is Null when no value is selected. Set DataValue to Null to make the lookup field blank.

 

Example

The following code example shows how to use a field of type Regarding.

var lookupItem = new Array;
lookupItem = null;

// This gets the lookup for the attribute regardingobjectid on the Task form.
lookupItem = crmForm.all.regardingobjectid.DataValue;

// If there is data in the field, show it in a series of alerts.
if (lookupItem[0] != null)
{
   // The text value of the lookup.
   alert(lookupItem[0].name);

   // The GUID of the lookup.
   alert(lookupItem[0].id);

   // The entity type name.
   alert(lookupItem[0].typename);
} 

StringThe following properties are available:

String properties Type Description
{Field}.DataValue A reference to a string object Get/set property.
{Field}.MaxLength Integer Get property.The maximum length of the string.


Example

The following code example shows how to use a field of type String.

var oField = crmForm.all.SOME_STRING_FIELD_ID;

var sValue = "String that might be too long.";

if (sValue.length > oField.MaxLength)
{
   sValue = sValue.substr(0, oField.MaxLength); 
}

oField.DataValue = sValue;

Display a CRM 4.0 PickList Display-Value in Reports and Queries

Microsoft CRM 4.0 stores picklist display values within the MetadataSchema in the StringMap table.  When creating custom reports or quieries a custom Scaler-Function is needed to show the picklist display vale.  To do this I wrote a simple function shown below called MapPickList that can be called in a SQL query to return a picklist displayvalue.

This example shows the CRM Contact table with a custom attribute called ShoeSize

SELECT     LastName, FirstName, dbo.MapPickList(‘contact’, ‘ShoeSize’, ShoeSize) AS DisplayValue

FROM  Contact

The output would look like this:

LastName            FirstName           DisplayValue
—————————————————————-
Smith                    Mark                     12.5
Estes                     Lowell                   10
Sue                        Jones                    7

And here is the SQL function.

CREATE FUNCTION MapPickList

(

/******Name of the CRM Entity we are querying******/

@entity varchar(50),

/******Name of the CRM Attribute we are querying******/

@attribute varchar(50),

/******The picklist int value stored by CRM******/

@value int

)

RETURNS varchar(500)

BEGIN

DECLARE  @return varchar(500)

SET @return = (SELECT StringMap.Value AS DisplayValue

FROM StringMap INNER JOIN MetadataSchema.Entity ON StringMap.ObjectTypeCode = MetadataSchema.Entity.ObjectTypeCode

WHERE (StringMap.AttributeName Like @attribute) AND (StringMap.AttributeValue = @value) AND (MetadataSchema.Entity.Name Like @entity))

return @return

END