Batching Brainteaser Explained


So, as some of you pointed out, the batching brainteaser does print out the “intersection” of GroupA and GroupB. But how exactly does this work?


Recall that when you access metadata on an item list during a task invocation, you will trigger batching – and this will essentially cause the item list to get filtered, causing the task to be invoked multiple times for each unique “batch” of items satisfied by the criteria you use to batch.


So, if you want to loop, you’d use meta-data value that is unique – such as %(Identity). The following example causes what would be considered as looping. Say you have an items defined as shown:


<ItemGroup>
        <
GroupA Include=file1.txt
/>
        <
GroupA Include=file2.txt
/>
        <
GroupA Include=file3.txt
/>
        <
GroupA Include=file4.txt
/>
</
ItemGroup
>


 <ItemGroup>
        <
GroupB Include=file1.txt
/>
        <
GroupB Include=file3.txt
/>
        <
GroupB Include=file5.txt
/>
</
ItemGroup
>


A call to the Message task as shown would cause four Message task invocations:


<Message Text=Item @(GroupA) has identity %(GroupA.Identity)/>


In this case, we have explicitly qualified the identity metadata by using the name of the item, but it is redudant because there is only one item in use when we invoke the task. However, when multiple items are involved, not qualifying the metadata will mean that that piece of metadata will get used against all items that are involved in the task invocation. The following task invocation example makes this clear:


<!– Print a header —>
<Message Text=|GroupA| – |Identity| – |GroupB|/>

<Message Text=|@(GroupA)| – |%(Identity)| – |@(GroupB)|/>


The output clearly shows the multiple batches that are formed because of this invocation when two item lists are involved, when using an unqualified metadata accessor like we used: 


|GroupA| – |Identity| – |GroupB|
|file1.txt| – |file1.txt| – |file1.txt|
|file2.txt| – |file2.txt| – ||
|file3.txt| – |file3.txt| – |file3.txt|
|file4.txt| – |file4.txt| – ||
|| – |file5.txt| – |file5.txt|


Once again, if you keep in mind that the items involved are filtered according to each unique value of the metadata that batching occurs on, then this makes sense.


So now, all you have to do really is to apply a condition that eliminates those batches that have empty values of either GroupA or GroupB – which leads to what we had as our CreateItem call in our brainteaser. Look at it again with that sharper batching eye and see if the answer emerges 🙂


<CreateItem Include=@(GroupA) Condition=‘%(Identity)’ != ” and ‘ and ‘@(GroupB)’ != ”>
    <
Output TaskParameter=Include ItemName=GroupC
/>
</
CreateItem
>


So what do you think? Too confusing or too cool? Would love to hear your thoughts!


[Author: Faisal Mohamood]


Comments (5)

  1. The State and Local Government Developers blog talks about the Requirements Authoring Starter Kit (RASK)….

  2. eugenez says:

    G’day,

    Very nice task – I did start with the solution first, but it was fun anyway.

    I have some small thingy to the solution though which I do not understand.

    You explained that when specifying condition containing two groups, union (kind of) will be created. Therefore, is the purpose of adding the condition "Identity !=  " to task only to add third element to the union? It appears if you do not add it, the condition will look upon each group as whole entity, and when you do add it, MSBuild looks upon group elements rather than on groups.

    Thanks beforehand.

  3. Troy Gould says:

    Please, please, please add this kind of info to the documents on MSDN.  You don’t know how many times people have run into this problem.  It took me a few months to realize this was what was happening, and I know many others that have had the same problem!

  4. Last time , I created an installer with a shortcut in the user’s start menu to a very simple application.

  5. Matthew Phillips says:

    Why do you you hide this info in a blog and not put it in MSDN proper?

    Apalling