Kids, don't try this at home!

Tips & Tricks for C#, ASP.NET and CRM

CRM 4 Incremental Numbering for any Entity

UPDATE 08/01/2009
- Project is now on CodePlex (http://www.codeplex.com/crmnumbering/)

MYOB can only take 8 characters and accountants don't like seeing cryptic Invoice Numbers that CRM generate, so we ended up writing a custom plugin that automatically incremented each invoice. Keeping extensibility in mind we made it work with any customizable entity. Here is how we did it.



We created a simple organization owned entity that held the type of entity you wanted to increment, the property/field you wanted to increment and the current/starting position.
The field to increment must be of type integer.

Next we wrote a plugin that hooked into the Pre-Create event synchronously, check the target, get the incremental settings for this entity, make sure the property specified is not in the property bag, increment the current number and update our custom entity with the newest number.

public void Execute(IPluginExecutionContext context)
{
    if (context.InputParameters.Properties.Contains("Target") &&
        context.InputParameters.Properties["Target"] is DynamicEntity)
    {
        DynamicEntity entity = context.InputParameters.Properties["Target"] as DynamicEntity;
        // simple query to get incremental settings for this entity
        IncrementalNumbering setting = GetSettings(context, entity.Name);
 
        // system generated, if its assigned ignore this record
        if (setting != null && !entity.Properties.Contains(setting.PropertyName))
        {
            int next = setting.CurrentPosition + 1;
            CrmNumberProperty increment = new CrmNumberProperty(setting.PropertyName, new CrmNumber(next));
            entity.Properties.Add(increment);
 
            // keep track of the latest id inside the custom entity
            setting.Increment(context, next);
        }
    }
}

GetSettings call above finds the matching setting, if it finds one it calls overloaded constructor below passing it the Dynamic Entity which then convert the CRM specific types into basic .NET types.

Here is the IncrementalNumbering class.
public class IncrementalNumbering
{
    public class Fields
    {
        public const string Id = "mag_incrementalnumberingid";
        public const string EntityName = "mag_entity_schema_name";
        public const string PropertyName = "mag_property_schema_name";
        public const string CurrentPosition = "mag_currentposition";
    }
 
    public IncrementalNumbering() { }
 
    public IncrementalNumbering(DynamicEntity entity) 
    {
        this.Id = (entity.Properties[Fields.Id] as Key).Value;
        this.EntityName = entity.Properties[Fields.EntityName].ToString();
        this.PropertyName = entity.Properties[Fields.PropertyName].ToString();
        this.CurrentPosition = (entity.Properties[Fields.CurrentPosition] as CrmNumber).Value;
    }
 
    public void Increment(IPluginExecutionContext context, int next)
    {
        using (ICrmService service = context.CreateCrmService(true))
        {
            this.CurrentPosition = next; // set before calling ToDynamic
 
            TargetUpdateDynamic target = new TargetUpdateDynamic();
            target.Entity = this.ToDynamic();
 
            UpdateRequest request = new UpdateRequest();
            request.Target = target;
 
            service.Execute(request);
        }
    }
 
    // include rest of the fields, but leave it for now
    public DynamicEntity ToDynamic()
    {
        DynamicEntity entity = new DynamicEntity(IncrementalNumbering.SchemaName);
        PropertyCollection properties = new PropertyCollection();
 
        properties.Add(new KeyProperty(Fields.Id, new Key(this.Id)));
        properties.Add(new CrmNumberProperty(Fields.CurrentPosition, new CrmNumber(this.CurrentPosition)));
 
        entity.Properties = properties;
 
        return entity;
    }
}

Here is the result


Bit of a hack with converting between CRM and .NET types, keep an eye out for another post where I'll be showing you how to wrap CRM entities so that you're only working with .NET types. If you want the full sample including code; send me an email.

Enjoy!
Posted: Oct 23 2008, 11:12 PM by gperera | with 11 comment(s) |
Filed under: , ,

Comments

Simon Jackson said:

This is great, bu are you sure that concurrent access will not issue the occasional duplicate number?

Perhaps a Mutex would help by ensuring that only one thread executes the code at a time?

Cheers

Si

# November 26, 2008 6:36 AM

gperera said:

hi Simon

We've not had any duplicate numbers for invoices so far, this is probably because the invoices are created automatically and are not created in quick succsession.

I simulated concurrent creations and it did duplicate the numbers.

You are correct, we can use a mutex or sync lock.

Cheers for finding the bug and suggestion.

# December 3, 2008 10:47 PM

Mira’s Blog » Blog Archive » How to create incrementing entity number using MS CRM 4.0 customization area? said:

Pingback from  Mira’s Blog  » Blog Archive   » How to create incrementing entity number using MS CRM 4.0 customization area?

# January 2, 2009 1:20 PM

grega_g said:

It doesn't work with lock(). Plugin could be ran by more than one process. use mutex instead.

# July 24, 2009 6:54 AM

gperera said:

Thanks grega, you are correct, Mutex will protect the plugin against multiple processes. I have updated codeplex.

# July 26, 2009 6:48 PM

ben said:

may I know how to implement in CRM4.0 ?

I have just registerd the .dll but don't know how to continue ...

Please ..

# November 8, 2009 10:34 PM

gperera said:

Hey Ben

Once you register the dll, create a step

Message: Update

Entity: <schema name of the entity you want to increment>

Stage: Pre

Pipeline: Synchronous

Then go into the crm settings section, you'll see 'Incremental Numbering', create a record for your incremental numbering entity.

# November 9, 2009 12:53 AM

Austin Jones said:

One suggestion on your implementation of Mutex is to wrap your _sync.ReleaseMutex() with finally { } to ensure that a blocked thread is released even if an exception is encountered.

# December 15, 2009 6:38 PM

gperera said:

Hi Austin, I'm not sure if that's required since the logic part is wrapped in a try catch

# December 16, 2009 5:41 PM

Bob G said:

I do not think mutex will work in a load balanced front end situation (with more than one front end server)

# March 10, 2011 2:55 PM

gperera said:

Hi Bob

You're correct, for load balanced servers you'll need to modify the code so that it checks if the number is available just before updating, this done in a loop with some millisecond sleeper works. (not reliable very high load, you might want to look at other possibilities like external db with a stored proc)

# March 14, 2011 4:52 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)