Apologies in advance for the long post...
I've just had a look at the COMB approach and although the creator did a good job figuring it out (http://www.informit.com/articles/article.aspx?p=25862&seqNum=1) he did so to cover the gap as it existed in SQL 2000. The author does later acknowledge the introduction of NewSequentialId() (http://www.jnsk.se/weblog/posts/combkiller.htm), but doesn't actually assess whether it's really any better than COMB (even though his blog title of "COMB Killer" implies he did). Two points of note from the original article is that the author states that if multiple records are created within 1/300th second that his approach would result in non-sequential GUIDs as his are only sequential to the granularity of a 6 byte datetime value (though probably not a point of concern for most databases) and that collisions are more likely within that timeframe due to there being less "random" bytes as 6 would be fixed for that 1/300th second block (but this weakness might prove a strength in the long run as collisions from 1/300th second block would impossible with another 1/300th second block for upwards of 77 years I think he mentioned).
I think if I were creating a disconnected application (e.g. local windows clients feeding back into a central DB via web services for example) COMB would probably work better as it's based on what time it was generated, not what machine it's on. This benefit to indexing when the data is consolidated would probably be enough to warrant integrating an external GUID generator, but not for single DB server implementations in my opinion. Another scenario to consider though are scenarios such as a DB hosted on a passive/active cluster where the active node occasionally switches as this would create a new "series" of GUIDs and could muck with indexing to varying degrees (I'm thinking of a scenario where the new MAC address results in GUIDs which are "lower" than the existing ones meaning any new inserts are slotted in the middle of the index). Any form of replication would generally result in this I'd think (e.g. log shipping to a disaster recovery site, true replication, etc). That said, I'm with Swin in that I think you should always use whats native to the environment unless you have a decent reason not to (e.g. performance, scalability, missing feature, etc).
As a result I believe NetTiers should be enhanced to support both COMB and NewSequentialId(). How that's achieved is the real question. If a DBA or software architect defines a default on a DB column then it should be used and not overridden by a code generator framework (as is the current situation with NewId() for example, but I think we're stuck with that one for reasons above). I'm not adverse to Phil's suggestion of using COMB when there is no default on the column, but only if the column does not allow nulls (as there are situations you may want to assign a GUID conditionally). So, if a GUID does not allow nulls, has no default and no value has been provided to the data access layer then creating a GUID in the data access layer would seem acceptable to me. I would prefer it be a configuration setting though as to what implementation gets used and for the moment the default would be "Guid.NewGuid()" with an alternate choice of "COMB". It wouldn't surprise me if another approach is created by somebody in the near future as COMB isn't perfect and could be improved again (maybe the same guy will create COMB 2.0). Does that sound ok to everyone? I don't mind doing the work to get it done.
My reason for suggesting "Guid.NewGuid()" as a default is that is how the NetTiers framework functions currently (meaning existing solutions using the framework shouldn't be affected) and I agree with Swin that COMB is not a native approach and I don't believe it's right to push a 3rd party approach (e.g. non-Microsoft) in a framework claiming to be following Microsoft best practice as that's what people will be expecting to see (regardless if the approach is better).
As for the OUTPUT clause, I have already implemented that in my local copy of the templates using a table variable and it works fine. Personally I'd prefer keeping with this approach rather than returning a rowset back to the data access layer as I'm not a fan of returning a collection of something with the assumption it always has only 1 item in it (though that approach would work better for custom procs with bulk updates perhaps). I had actually started using the OUTPUT clause to retrieve the computed columns as well, but have uncovered that the OUTPUT clause reads the newly inserted/updated/deleted record before any triggers fire. So if you have any triggers altering the record which subsequently change the computed column values, the OUTPUT clause may result in you getting differing results than you expected. I can't remember a situation where I've used a trigger in this way and would probably have to question the necessity, but that's not for me to decide and the framework shouldn't either. Therefore I'll leave the current approach for retrieving the computed values and only use the OUTPUT clause for getting newly the GUID created via NewSequentialId() (which is a shame as the OUTPUT approach was a lot more elegant than the current SELECT approach IMO). This approach will be implemented for any situation where NewSequentialId() is used, regardless of SQL 2005 features being enabled as there's no alternative really and that default is only supported in SQL 2005. I figure we're best to leave NewId() being created in the data access layer for now due to the lack of a method for cleaning retrieving a DB generated one in SQL 2000 (as it can only be accomplished via referencing an alternative key as I understand it and not easy for a code generator to figure out).
BTW: Thanks Phil for making me aware of COMB as it has been an interesting exercise researching it. Not sure how I missed it when researching NewSequentialId() to be honest as there's the odd article out there referring to both. Even though I now think COMB is generally better (less predictability, better consolidation from multiple machines, etc) NewSequentialId() meets the requirements where we've used it so far and has the advantage of being native.