Altinet
  • Home
  • Blog
  • Contact





Managing execution order in runtime

On 16 Apr, 2014
Uncategorized
By : Bruno Samardzic
No Comments
Views : 3757

I had a pretty common problem with regards to inserting into database tables. As you probably know, depending on your data and foreign keys, you need to insert data in a specific order, for instance, you first need to insert invoice record, and only after that you can insert invoice items.
This problem has been already solves so many times, and in different ways (some ORMs inspect your tables and determine dependencies and what goes first, others rely on you to define the order by defining dependencies, and some of them just leave it to you to do the updates in a proper order).
I faced this problem before, when developing an SPA, and the problem with SPAs is that you may not necessarily do DB operations when doing the UI operations (which would mean you force operations in a particular order), instead doing a Flush after you are done editing an invoice (for instance) and sending a set of data which need to be updated or inserted.

To make matters worse, if you code generate your data it can get pretty complicated, or you just do the whole thing with custom coding, circumventing that nice smart code you spent so much time generating.
It got me thinking on how to go about it and force a particular execution order, and i decided to make a custom class which would do it.
Some code samples:

public static void Save(this Template myTemplate)
{
	foreach (TemplateField subTemplateField in myTemplate.TemplateFields)
	{
		subTemplateField.TemplateGuid = myTemplate.TemplateGuid;
		result += subTemplateField.Save();
	}

	foreach (TemplateTable subTemplateTable in myTemplate.TemplateTables)
	{
		subTemplateTable.TemplateGuid = myTemplate.TemplateGuid;
		result += subTemplateTable.Save();
	}
} 

I needed that TemplateTables do a Save before TemplateFields, since TemplateFields hold a reference to TemplateTables. The problem is that this code is generated, so if i wanted to change the order of execution, i would have to copy all this code, modify it and keep it updated whenever i code generate again. Very very daunting.
So i thought of a ExecOrder class. How does it work?
I have this factory method which gets the proper ExecOrder object for a proper class and method:

        public ExecOrder GetExecOrder(string classMethodName)
        {
            switch (classMethodName)
            {
                case "TemplateService.Save":
                    return new ExecOrder("TemplateTables");
            }
            return new ExecOrder();
        }

See that “TemplateTables” argument? It tells execOrder that should be the first code that needs to be executed, and the rest of the code sections can execute after that.
If you need a particular order for 3 code snippets (say “TemplateTables”, “TemplateFields” and then “TemplateSubFields”) you would initialize it with


      return new ExecOrder("TemplateTables","TemplateFields");

The third one is omitted because you don’t really need it in the argument list if you just wanted it executed AFTER the first 2. So how do you apply it to the previous code?

public static void Save(this Template myTemplate)
{
     var execOrder = GetExecOrder("Templates.Save");
     while (execOrder.CheckDone())
     { 
	if (execOrder.Check("TemplateFields"))
		foreach (TemplateField subTemplateField in myTemplate.TemplateFields)
		{
			subTemplateField.TemplateGuid = myTemplate.TemplateGuid;
			result += subTemplateField.Save();
		}

	if (execOrder.Check("TemplateTables"))
		foreach (TemplateTable subTemplateTable in myTemplate.TemplateTables)
		{
			subTemplateTable.TemplateGuid = myTemplate.TemplateGuid;
			result += subTemplateTable.Save();
		}
     }
} 

The execOrder on first CheckDone always returns true, it makes a first pass through the code and updates it’s list on what needs to be executed and in what order. It adds to list the tokens that are not on it. It also executes the first command in list, and any other that is aligned with the list. It makes as many passes as needed to execute everything from the list in the correct order, but if something’s not in the loop, but it is on the list (a dummy token) it will skip it as well.
If the list is empty it will just execute everything as it comes. It is important to have all the code inside the loop tokenized (inside an if block), otherwise the code will be executed at every pass.

And there you have it, i’m not sure this kind of code falls into best practice (though often you don’t have much choice, so you make the most of it:), but it’s pretty good for controlling the flow and very robust (it tolerates additional and missing tokens). You could use it for firing triggers and events in a custom order (for different clients or uses), or whatever else you see fit.
And lastly, the code for ExecOrder:


    public class ExecOrder
    {

        private List<string> _tokenOrder;
        private int _current = 0;
        private bool _isCompleted;

        public ExecOrder(params string[] tokenOrder)
        {
            if (tokenOrder != null && tokenOrder.Length > 0)
                _tokenOrder = tokenOrder.ToList();
        }

        public bool Check(string token)
        {
            if (_tokenOrder == null)
            {
                _isCompleted = true;
                return true;
            }
            if (_tokenOrder.Count > _current && _tokenOrder[_current] == token)
            {
                _current++;
                _currentNotFound = false;
                return true;
            }
            if (!_tokenOrder.Contains(token))
            {
                _tokenOrder.Add(token);
            }
            return false;
        }

        private bool _currentNotFound;
        public bool CheckDone()
        {
            if (_currentNotFound) _current++;
            _currentNotFound = true;
            return _isCompleted || (_tokenOrder==null && _current>0) || (_tokenOrder != null && _current >= _tokenOrder.Count);
        }
    }



Previous Post Next Post 

About The Author

Bruno Samardzic


Number of Posts : 45
All Posts by : Bruno Samardzic

Leave a Comment

Click here to cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>





Recent Posts

  • Angular vs React: round 2
  • Why programming is hard
  • Orchard Workflows, undocumented gem
  • The React Redux
  • React.js invoicing CRUD application, part 2: Description

Recent Comments

  • Angshuman on Animation for starred grid rows and columns using xaml
  • Advanced Excel Training in Lucknow on Angular vs React: round 2
  • Reginald Sophomore on My example of Angularjs directive
  • Slobodan on Angular and Breeze – story so far.
  • Bruno Samardzic on Reaction to Ember-forged Durandal Angularly Knocking out my Backbone, or my JS MVC framework research conclusion.

Contact

Altinet d.o.o.

OIB: 97429091194

Čulinečka cesta 146, Zagreb

Tel: +385 (1) 2946 819

Mob: +385 (98) 210 756

IBAN: HR4323400091110406470

Latest tweets