tag:blogger.com,1999:blog-46280181848980964172024-03-13T05:03:02.701-07:00Random Wibblings from the Monkey HouseMusings on .NET, architecture and code stuffs from a veteran dev monkey and Sitecore Technology MVPMonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.comBlogger22125tag:blogger.com,1999:blog-4628018184898096417.post-15887206209539186382018-05-09T00:39:00.001-07:002018-05-09T00:42:10.987-07:00Sitecore Buckets and Improving bulk import speedHello.<br />
<br />
I ran into a problem <a href="https://sitecore.stackexchange.com/questions/2184/what-is-the-fastest-way-to-delete-thousands-of-items-in-the-content-tree" target="_blank">while trying to bulk insert items into a bucket in code</a>, using the Glass Mapper SitecoreService - insert speed was very slow (10,000 items took 50 minutes). Deleting all items from the bucket was also fairly slow.<br />
<br />
The solution in code is basically the same as the Powershell equivalent in the link above: -<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> using (new Sitecore.Data.BulkUpdateContext())</span><br />
<span style="font-family: Courier New, Courier, monospace;"> using (new SecurityDisabler()) // yes yes I know</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> foreach (var item in data)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> sitecoreService.Create(folderItem, item, false, true);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<br />
Yes I know I <a href="https://stackoverflow.com/questions/21456939/sitecore-userswitcher-vs-securitydisabler" target="_blank">should be using a UserSwitcher instead of disabling all security</a>..<br />
<div>
<br /></div>
<div>
Total import time down from 90 minutes to 6. Not bad :)</div>
<div>
<br /></div>
<div>
<br /></div>
MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-84559793406254883402018-04-11T18:49:00.002-07:002018-04-11T18:51:25.081-07:00SIFLess for easy Sitecore 9 installationLazy me, here's a link to an article: -<br />
<br />
<a href="http://www.rockpapersitecore.com/2017/10/introducing-sif-less-for-easy-sitecore-9-installation/" target="_blank">http://www.rockpapersitecore.com/2017/10/introducing-sif-less-for-easy-sitecore-9-installation/</a><br />
<br />
h/t to RockPaperSitecore for this. Works well, by the way :)MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-4327406246389969202017-02-01T21:15:00.002-08:002017-02-01T21:15:31.329-08:00:^)<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-mN0vFvPj60I/WJK-80sBrQI/AAAAAAAAAZ4/4GKawn9PuoYClfjFpc9BJZFp3m4UzpipwCLcB/s1600/Sitecore_MVP_logo_Technology_2017.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="391" src="https://4.bp.blogspot.com/-mN0vFvPj60I/WJK-80sBrQI/AAAAAAAAAZ4/4GKawn9PuoYClfjFpc9BJZFp3m4UzpipwCLcB/s400/Sitecore_MVP_logo_Technology_2017.png" width="400" /></a></div>
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-AV837TSIF0o/WJLARj3J6RI/AAAAAAAAAaE/xqhxr7wWJbYGdnFrWKIQqta03PWPBqO7gCLcB/s1600/Youre-God-Damn-Right-Walt-In-Breaking-Bad-Reaction-Gif.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://4.bp.blogspot.com/-AV837TSIF0o/WJLARj3J6RI/AAAAAAAAAaE/xqhxr7wWJbYGdnFrWKIQqta03PWPBqO7gCLcB/s320/Youre-God-Damn-Right-Walt-In-Breaking-Bad-Reaction-Gif.gif" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-lRVnGDz15yU/WJLAZnCIt5I/AAAAAAAAAaI/7FF6fiBo1CsptJT0jgkNZtPsourV0ETigCLcB/s1600/Cc2l0BQ.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="https://1.bp.blogspot.com/-lRVnGDz15yU/WJLAZnCIt5I/AAAAAAAAAaI/7FF6fiBo1CsptJT0jgkNZtPsourV0ETigCLcB/s320/Cc2l0BQ.gif" width="320" /></a></div>
<br />MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-49764544095749005592017-01-12T23:49:00.002-08:002017-01-12T23:49:36.381-08:00CodeDen's - Sitecore Habitat Transformer<a href="http://habitat.demo.sitecore.net/" target="_blank">What is Sitecore Habitat ? </a><br />
<br />
It's an example implementation of the <b><a href="http://helix.sitecore.net/" target="_blank">Helix</a></b> design principles and conventions for a Sitecore project.<br />
<br />
Dennis Lee has thoughtfully provided a nice and safe means of accelerating the process of re-implementing Habitat (the demo) in your own project.<br />
<br />
<a href="https://codingdennis.blogspot.com.au/2017/01/sitecore-habitat-transformer.html" target="_blank">Get it here</a><br />
<br />
<br />MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-27444448063269636272016-10-06T01:23:00.002-07:002016-10-06T01:23:20.238-07:00RCSThis is the TLA for a new venture which I, as senior Website-Building Fromage to the Gentry, have been asked to make.<br />
<br />
My brief was to make it a) simple to edit and b) editable by simples, so I decided to re-visit my own CMS with a view to "getting this done" (TM). (PS Sorry Sitecore, but you're not going to stoop to this end of the market or their budgetary constraints !)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-Mg_Dhj54cCk/V_YJpq56I6I/AAAAAAAAAXI/N9eFdZf-lbQ5K9glpRbxbCSpTZBR0KiTACLcB/s1600/Z8MEcb7.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-Mg_Dhj54cCk/V_YJpq56I6I/AAAAAAAAAXI/N9eFdZf-lbQ5K9glpRbxbCSpTZBR0KiTACLcB/s1600/Z8MEcb7.jpg" /></a></div>
<br />
<br />
So as I've basically copy-paste inherited my CMS into hmmm 5 or 6 websites now, with the usual "it deviates here" shenanigans that you get when copying and pasting an entire Visual Studio solution and databases for re-use.<br />
<br />
I've done some more sensible stuff, including modularisificating my CMS framework into, let's see now, actual modules (the CMS and its base stuff is now in its own assembly, yay !)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-pC1S6YYvUGA/V_YIZjevKOI/AAAAAAAAAW8/udODbylullA-N3uX_X9xYA84xqgHYVNEgCLcB/s1600/52-sense-this-picture-makes-none.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://2.bp.blogspot.com/-pC1S6YYvUGA/V_YIZjevKOI/AAAAAAAAAW8/udODbylullA-N3uX_X9xYA84xqgHYVNEgCLcB/s320/52-sense-this-picture-makes-none.jpg" width="255" /></a></div>
<br />
I've studied Bootstrap and the whole "semantic HTML" concept quite a lot at <a href="http://www.ping-works.com.au/" target="_blank">PING Works</a>, mainly as a side-effect of being asked to POC <a href="http://habitat.sitecore.net/" target="_blank">Sitecore Habitat</a>. I'm also trying to do this in my own CMS; with the objective being to understand semantic HTML, modularity and re-skinnability as central tenets to both Sitecore builds (i.e. high-end clients) and my own (i.e. not so).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-4oEFI52VuTg/V_YJ6FRDFrI/AAAAAAAAAXM/gQ3jEzRauXYOMa8D5qup-Gcsq4svNSz7ACLcB/s1600/u69jRvb.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="274" src="https://1.bp.blogspot.com/-4oEFI52VuTg/V_YJ6FRDFrI/AAAAAAAAAXM/gQ3jEzRauXYOMa8D5qup-Gcsq4svNSz7ACLcB/s320/u69jRvb.gif" width="320" /></a></div>
<br />
<br />
What in the hell am I talking about ? Dunno mang, watch this space as I reveal all ! Or just a bit. Or maybe nothing. More to follow. Maybe.<br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-73840034709386211202016-05-06T02:01:00.001-07:002016-05-06T02:19:39.272-07:00Theatre on the River - reskinSo,<br />
<br />
My sister runs a very successful drama teaching company in London, and <a href="http://theatreontheriver.com/" target="_blank">her current site</a> is nice <b>but</b> it uses device detection (<a href="https://51degrees.com/" target="_blank">51degrees.mobi</a> if you're interested) for mobile/tablet which is no longer the cool way to handle mobile traffic (as now enforced by our Google overlords).<br />
<br />
Instead, sites must be <i>responsive</i> which is hardly a term new to anyone reading this drivel but for those of you who've been living in a cave eating beetle dung for the last few years, "responsive" is an HTML 5-based concept where the site's presentation layer (the HTML and CSS) must adapt to the device the site is rendering into.<br />
<br />
This means no cop-out of sniffing the device server-side and redirecting to a <b>/mobile</b> set of layouts/masterpages/etc but instead - there is just one site to rule them all. Which is done using CSS media queries.<br />
<br />
This isn't the first responsive site I've worked on, ohnono. My brother runs a very successful glass machinery oligarchy in Rugby (home of the game, Rugby fans!) and his site was the first independent site I rebuilt in a responsive style.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-rka8Fu7VINM/VyxZhOMSc2I/AAAAAAAAAUU/-Nl6uEk08BYDb0E3Cdpe_f6MshOOGy6sgCLcB/s1600/checkem.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-rka8Fu7VINM/VyxZhOMSc2I/AAAAAAAAAUU/-Nl6uEk08BYDb0E3Cdpe_f6MshOOGy6sgCLcB/s1600/checkem.jpeg" /></a></div>
<a href="http://glassmachines.co.uk/" target="_blank">Glass Machinery Solutions Ltd</a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
As you can see, it looks good on<br />
<br />
a) desktop,<br />
b) tablet, and of course<br />
c) mobile<br />
<br />
All served from just the one URL and this pleases our Google overlords, who will continue to rank your site in accordance with their holy scriptures. And not penalise you for redirecting to effectively another site (or worse, <b>your site is not mobile-friendly at all </b>and therefore you fail at everything).<br />
<br />
I'm no front-end guru; never have been, don't want to be either. It'll push other, more useful stuff out of my head such as being able to order a beer, or pulling a wheelie between lanes of traffic. What I am good at doing with front-end stuff is glueing someone else's efforts together into an ASP.NET application.<br />
<br />
I do understand media queries, they're not hard. I do not however have the necessary skill/patience to make sure the resulting CSS & HTML functions across all browsers, devices and small hairy marsupials.<br />
<br />
So ! <a href="http://html5up.net/" target="_blank">HTML5Up </a>to the rescue. These guys offer a bunch of free, responsive skins (a bunch of CSS, JavaScript and sample HTML pages) for you to use, as long as you acknowledge their awesome efforts (no probs there guys!).<br />
<br />
They also have even more elaborate skins you have to pay for, not a lot, but whether you choose to go the free or paid route, I can highly recommend their work.<br />
<br />
<a href="http://theatreontheriver-backstage.azurewebsites.net/index" target="_blank">The new site</a> needs some image work and polishing (so don't mail me about images being different heights or whatever COS YEAH I KNOW) but I'm sure you'll agree, it looks better. For minimal outlay.<br />
<br />
People dedicating their lives to making awesome HTML 5 skins - you have my utmost respect and infinite gratitude.<br />
<br />
BTW please don't spam my sister's email using the Contact Us form.<br />
<br />
BTTW I'll know who did it and I will find you<br />
<br />
BTTTW Look at me. I'm the captain now.<br />
<br />
:DMonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-53528690391911969932015-06-04T02:57:00.001-07:002015-06-04T03:03:32.596-07:00Be careful what you delete for II - Judgment DayA while back I <a href="http://random-monkey-wibblings.blogspot.com.au/2012/05/be-careful-what-you-delete-for.html">posted this</a> regarding deleting data from Sitecore's Analytics database.<br />
<br />
TL;DR - Sitecore 6.4 (and possibly other versions using SQL-based analytics) do not want you to truncate the IPOwner table. Analytics stops working.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-QMlLUd2B7LQ/VXAe0bMpNzI/AAAAAAAAAP8/RICcxXidgec/s1600/Do_Not_Want.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="179" src="http://4.bp.blogspot.com/-QMlLUd2B7LQ/VXAe0bMpNzI/AAAAAAAAAP8/RICcxXidgec/s320/Do_Not_Want.jpg" width="320" /></a></div>
<br />
<br />
Lo and behold, we discover today that one of our Sitecore applications hasn't been collecting analytics for a while. Investigation of the database revealed - gasp - <i>no data in the IPOwner table</i> <i>!!!</i><br />
<i><br /></i>
The Sitecore logs revealed a multitude of Foreign Key constraint violations; specifically the foreign key IP.IPOwnerID - IPOwner.IPOwnerID. It's trying to add a row to the IP table using an IPOwnerID that does not exist.<br />
<br />
Wait, what ? There aren't any rows in IPOwner ?<br />
<br />
Suspecting magic GUID foul play and thinking that Sitecore is perhaps expecting a row to be there, we crack open a fresh copy of Sitecore 6.4's OMS database and sure enough, hiding in there was this little fella: -<br />
<br />
<table style="border: 1px solid black; font-size: 9pt;">
<thead>
<tr>
<td>IpOwnerID</td>
<td>Name</td>
<td>Country</td>
<td>VisitorIdentification</td>
<td>ExternalUser</td>
</tr>
</thead>
<tbody>
<tr>
<td>9F28FB1A-BDDA-4CE6-9521-D7E6C6D8BB9D</td>
<td>(Pending)</td>
<td>(Pending)</td>
<td>0</td>
<td></td>
</tr>
</tbody></table>
<br />
<br />
And it all makes sense. While waiting for MaxMind GeoIP service to return something, Sitecore is using <i>this guy</i> as the IPOwner for a new session until the queued service lookup completes (hopefully), so it can write some meaningful location data to the IP record.<br />
<br />
Added this row.. tested the site.. analytics starts recording stuff !<br />
<br />
So now we know. Delete all the IPOwner rows if you want, just make sure this row finds its way back in.MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-49966295531097000432013-03-19T05:29:00.001-07:002013-03-19T05:29:18.873-07:00SQL Row_Number() OVER and how to cure indeterminate sort orderThere's been plenty of wibbling on Stack Overflow about how paging and sorting at SQL Server level using the Row_Number() function can produce records ordered unpredictably between repeated executions of the same query; perhaps you wouldn't normally do this, perhaps you would and as required by my scenario, I did.<br />
<br />
And saw it myself - the variations weren't great but they <i>were</i> there and that's annoying.<br />
<br />
I checked and double-checked my stored procedure - it was doing what it was supposed to.<br />
<br />
Came across this via Stack Overflow - <a href="http://msdn.microsoft.com/en-us/library/ms186734.aspx">http://msdn.microsoft.com/en-us/library/ms186734.aspx</a> - and I'll repeat the most pertinent part here: -<br />
<br />
<span style="color: #9fc5e8; font-family: Georgia, Times New Roman, serif;"><i>There is no guarantee that the rows returned by a query using ROW_NUMBER() will be ordered exactly the same with each execution unless the following conditions are true: -</i></span><br />
<span style="color: #9fc5e8;"><br /></span>
<ul>
<li><span style="color: #9fc5e8; font-family: Georgia, Times New Roman, serif;"><i>Values of the partitioned column are unique.</i></span></li>
<li><span style="color: #9fc5e8; font-family: Georgia, Times New Roman, serif;"><i>Values of the ORDER BY columns are unique.</i></span></li>
<li><span style="color: #9fc5e8; font-family: Georgia, Times New Roman, serif;"><i>Combinations of values of the partition column and ORDER BY columns are unique.</i></span></li>
</ul>
<br />
<h3>
<span style="color: yellow;">How to fix this ?</span></h3>
So - Microsoft themselves admit this is a problem. There is of course a solution, and mine was a table variable.
<br />
<pre class="brush: sql">
DECLARE @IDTable TABLE
(
InvoiceID INT,
RowNumber BIGINT,
TotalRowCount BIGINT
)
<br />
</pre>
<br />
Because the actual results my query returns contained a number of identical field values in many cases (same Customer Name, same Status.. etc) the three rules outlined in the MSDN article weren't being met; hence the problem. You <i>can</i> guarantee the order by stripping the columns returned from the actual query back to a bare minimum - a key field (InvoiceID in my example), the RowNumber itself and (optionally) the result of the partition column expression.<br />
<br />
Having defined our table, I then run the complete query but returning only those 3 fields needed: -
<pre class="brush: sql">
INSERT INTO @IDTable (InvoiceID, RowNumber, TotalRowCount)
SELECT * FROM
(
SELECT DISTINCT i.InvoiceID,
Row_Number() OVER
(
ORDER BY
CASE
WHEN @SortExpression = 'DateCreated'
THEN i.DateCreated
END ASC,
-- snip - long list of fields to order by
) AS RowNum,
COUNT(*) OVER(PARTITION BY 1) as TotalRowCount
FROM ..
WHERE ..
) results
WHERE RowNum
BETWEEN (@PageIndex * @PageSize + 1)
AND ((@PageIndex * @PageSize) + @PageSize)
ORDER BY RowNum
<br />
</pre>
That deals with correct ordering of results; now run another query to join back to @IDTable, this time also retrieving all the coulmns needed: -
<pre class="brush: sql">
SELECT i.InvoiceID, c.CustomerName, .. etc
FROM @IDTable idt
INNER JOIN Invoice i WITH (NOLOCK) ON idt.InvoiceID = i.InvoiceID
INNER JOIN Customer c ..
-- and so on
<br />
</pre>
<br /><br />
Ok so there's some overhead involved with running two queries as opposed to one; but the execution time is still fast and it gives me exactly what I want. You should have seen what was happening before..<br />
MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-82599601243695367532013-03-06T02:06:00.002-08:002013-03-06T02:06:43.744-08:00Sitecore - Illegal characters in pathMeh.<br />
<br />
<br />
<code>
/// checks for the existence of illegal characters in the URL, these being " < > | and SPACE<br />
/// for some reason Sitecore's Sitecore.Pipelines.PreprocessRequest.FilterUrlExtensions pipeline<br />
/// component doesn't handle the exception<br />
///<br />
/// FilterUrlExtensions.Process > Sitecore.Web.RequestFilter.Process > RequestFilter.IsBlocked > RequestFilter.GetExtension<br />
/// > System.IO.Path.GetExtension > System.IO.Path.CheckInvalidPathChars = where it goes bang, and isn't handled<br />
/// <br />
/// This component fixes this behaviour by stripping illegal chars and then re-writing the URL using HttpContext.RewritePath<br />
///<br />
/// Note that for some reason, if IIS Static File Compression is enabled for the site, this can cause resources to<br />
/// be returned to the browser with the correct encoding type (GZIP) but the browser fails to parse them<br />
///<br />
/// Don't know why this is<br />
///<br />
/// For this reason, the URL is only rewritten if the request URL contains these illegal chars
</code>
<br />
<br />
Let's just say this has caused problems with custom pipeline components I have worked on.MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-12767238951128845032012-05-11T07:21:00.000-07:002012-05-11T07:41:30.761-07:00Diagnosis vs DesignThis is a subject close to my heart, and my abilities too.<br />
<br />
I am ok at diagnosis, but by no means a ninja - and sometimes as a solution architect you're going to need to diagnose a problem. Some are easy. Some are not.<br />
<br />
I am from the design school of systems architecture which means doing it right in the first place. I can hold court on OO design til the cows come home, and I can design you a domain model that will model your system's data and - most importantly - its behaviour. Cleanly, concisely and to the point of your requirement.<br />
<br />
I can do this across a huge range of technologies - web front end, Sitecore, Kentico, WCF, ServiceStack, Biztalk, MSMQ, SQL, Oracle. The building blocks of a lot of .NET solutions.<br />
<br />
What I'm not so good at - compared to the above - is diagnosing where and how things are going wrong in an existing solution. I tip my hat to a select few who can do this better than me.<br />
<br />
I can diagnose things that are wrong to a certain degree, and you can and should too. Today I had to sort out a non-working ASP.NET app. Here's what I did, in 10 minutes: -<br />
<br />
<ul>
<li>Installed the IIS6 metabase compatibility components</li>
<li>Ran aspnet_regiis /i to install ASP.NET</li>
<li>Set the App Pool's identity to Local System</li>
<li>Set permissions on folders</li>
</ul>
<div>
This got the guy going, and I revelled slightly in my ability to spot what was wrong and correct it.</div>
<div>
<br /></div>
<div>
But problems I've seen in the past (and recently) have been a whole lot hairier and have required more tools, and more knowledge.</div>
<div>
<ul>
<li>.NET Reflector - this thing is a life saver in so many situations. What does this DLL do ? Let's find out..</li>
<li>SQL Profiler - now this one I do know well. What's being sent to the server ? Answer in confidence. SQL Profiler is your friend</li>
<li>ANTS Memory Profiler - nice, but a bit bloated. Handy, but the daddy is...</li>
<li>WinDebug - see the Matrix as it truly is. Here is where your memory is being allocated. And why</li>
</ul>
<div>
I'll tip my hat to some colleagues of mine past and present who can do this <b>diagnosis</b> phase of systems engineering way better and quicker than I can: -</div>
</div>
<div>
<br /></div>
<div>
<a href="http://weblogs.asp.net/pglavich/">A guy I knew at Datacom</a> who showed me The Way regarding debugging a live app using WinDebug
</div>
<div>
<br /></div>
<div>
<a href="http://www.linkedin.com/pub/nick-harris/4/48a/172">Another guy at Datacom</a> who worked for me on an app of unfathomable architecture, and is the only person I know to date who got WS-AT working over MS DTC. We spent a pleasant evening, actually entire day and night, debugging a WCF sync service that if I'd had more say would never have existed.. another story ..
</div>
<div>
<br /></div>
<div>
<a href="http://www.linkedin.com/in/richardhauer">A person I work for now</a>, who can cut razor-like to the cause of and solution to many problems using the weapons in his arsenal, which are mostly Reflector but he also brings his networking knowledge to bear on things I don't get. Like Nick, an awesome troubleshooter
<br />
<div>
<br /></div>
<div>
Working with all of these dudes has humbled me when finding problems. These guys can pick the bones of a solution to the n-th degree and tell me what is and isn't right.</div>
<div>
<br /></div>
<div>
I can do this to a degree, but I think I have a different mindset. I design. I usually do it well.</div>
<div>
<br /></div>
<div>
Both skillsets are needed when doing big stuff. </div>
<div>
<br /></div>
<div>
Which are you ? Can you do both at the outer edges of ability ? I'm not sure anyone can.</div>
<div>
<br />
<br />
<br />
<br /></div>
</div>
MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-87775783018703634852012-05-11T06:40:00.001-07:002012-05-11T06:42:38.721-07:00Be careful what you delete for...Be very careful deleting stuff from a Sitecore Analytics database before you hand it over to your hosting company.<br />
<br />
The usual approach is to clear the Page, PageEvent and Session tables because these will be full - many months worth of team dev, in my case - of locally registered page views.
BUT - Don't get overzealous and delete the contents of the IPOwner table.<br />
<br />
Sitecore Analytics refused to do anything when I did this. Required inspection of the logs, which revealed a problem with some record not actually existing in IPOwner, even though a cursory inspection showed that this logged unique IP's for a session.<br />
<br />
Delete these with extreme caution... because analytics stops working, period !MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-46645046809355308202012-04-17T05:19:00.001-07:002012-04-17T05:19:37.288-07:00Javascript FrameworksRichard <a href="http://www.hanselman.com/blog/TheBigGlossaryOfOpenSourceJavaScriptAndWebFrameworksWithCoolNames.aspx">sent this list of Javascript / Web frameworks</a> around the office today.<br />
<br />
The stupendously named <a href="http://batmanjs.org/">batman.js</a> caught my eye, as I am prone to following daft names, although my knowledge of <a href="https://www.google.com.au/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CFAQFjAD&url=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FCoffeeScript&ei=jF6NT9b-MKyfiAfryIH8DA&usg=AFQjCNFJot6_p0I0qLkJVwu39UVfrm-50A&sig2=HfJTCdGC_MrGA_BO02CsVQ">Coffeescript </a>is not great (I've had a play).<br />
<br />
However, the even more daftly named <a href="http://mustache.github.com/">Mustache </a>and it's big brother Handlebar.js (where do people get these names from ?) are more my thing and I am playing with them now. More to follow.MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-50504692410421741322012-04-17T05:07:00.001-07:002012-04-17T05:09:11.816-07:00Initial Thoughts on RavenDBIt's good.<br />
<br />
More to follow :)<br />
<br />
<br />
<br />
But seriously, it's good and I'm scratching around the surface at the moment. I prefer its simpler-use approach to document (i.e. object) storage compared to Mongo. I like the fact it's natively JSON and I can serialize an entire object graph in one go.<br />
<br />
I like the fact that I can embed it it an application. As in - embed the server.<br />
<br />
Rumour is that Sitecore 7.0 is going to support it. Interesting. We at <a href='http://www.5limes.com.au'>5 Limes</a> may find a use for it sooner rather than later.<br />
<br />
And I'm currently exploring <a href='http://ravendb.net/docs/theory/indexes/docs-http-indexes-map-reduce'>the way it implements Map/Reduce indexes</a><br />
<br />
More to follow. Much more probably - this is my R & D subject at work, and I have to present it next week. Wonder if I can use it to present CQRS to the team in my next project ?MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-21460763737531828992012-02-10T04:57:00.000-08:002012-02-10T05:02:26.739-08:00nHibernate 3.0 DateTimesOk, so - this sucks.<br />
<br />
I want to be able to filter date ranges in an NH 3.0 query, and I don't want to have to first scan the whole table and then feed the results through LINQ to get my range. This table could contain millions of rows and my query will be hit on each request of a certain page.<br />
<br />
This works: -<br />
<br />
<pre>public IList<invoice> InvoiceSearch(InvoiceSearchCriteria criteria)
{
IList<invoice> list = null;
using (var session = SessionFactory.OpenSession())
{
var query = session.QueryOver < Invoice > ();
if (criteria.DateCreatedFrom != null)
{
query = query.AndRestrictionOn(x => x.DateCreated).IsBetween(criteria.DateCreatedFrom.Value).And(criteria.DateCreatedTo.Value);
}
.. snip
</pre><br />
What I'm doing here is filtering my results by a date range using nHibernate.Criterion.Lambda.IQueryOverRestrictionBuilder's innate ability to write good SQL and therefore limit the set I am querying. So far so good.<br />
<br />
I have a requirement to show all thingos (Invoices in this case) in a given month and year. According to those that know, this is simply (?) solved by mapping a YEAR and MONTH function to my Fluent entity, and then querying by those properties in my QueryOver expression, thusly: -<br />
<br />
<pre>Entity: -
public virtual int InvoiceYear { get; set; }
public virtual int InvoiceMonth { get; set; }
Map: -
Map(x => x.InvoiceYear).Formula("SELECT YEAR(DateCreated)");
Map(x => x.InvoiceMonth).Formula("SELECT MONTH(DateCreated)");
</pre><br />
and then doing suchlike in my querying codeage: -<br />
<br />
<pre> list = session.QueryOver<invoice>()
.Where(x => x.InvoiceYear == year)
.And(x => x.InvoiceMonth == month)
.List();
</pre><br />
<br />
<br />
Well - it doesn't work. nHibernate throws a fit when trying to compile the query expression.<br />
<br />
In the end, the only workable solution - one that doesn't involve a complete table scan into NH entities and from there a filter, cos that'll be scalable !!! - is as follows: -<br />
<br />
<pre>using (var session = SessionFactory.OpenSession())
{
DateTime from = new DateTime(year, month, 1, 0, 0, 0),
to = new DateTime(year, month, DateTime.DaysInMonth(year, month), 23, 59, 59);
list = session.QueryOver < Invoice > ()
.Where(x => x.Active == true)
.AndRestrictionOn(x => x.DateCreated).IsBetween(from).And(to)
.List();
}
</pre><br />
Got to say that annoys me somewhat, but then I guess I need to spend more time studying expression trees. On the other hand, I have business requirements that a) need solving and b) must scale to meet demand.<br />
<br />
Wish me luck :)MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-46200283350606550302011-08-29T19:24:00.000-07:002011-08-29T19:25:35.479-07:00Fun with Helicon ApeMinor inconvenience with someone changing a Sitecore item name (and thus URL) today; this led to stale links from Google, which had not yet re-indexed the new URLs.<br />
<br />
Bit of a fail because we should have put a 301 redirect in place to handle this, which leads me on to the reason for this post. Try as I might I couldn't find a simple example for using the IIS7 Helicon Ape plug-in to map the start of a URL/* to a new URL/*, for example: -<br />
<br />
<pre><span class="Apple-style-span" style="color: yellow;">/products/old-category/*
i.e. /products/old-category/sub-category/thing/whatever</span>
</pre><br />
to<br />
<br />
<pre><span class="Apple-style-span" style="color: yellow;">/products/new-category/*
i.e. /products/new-category/sub-category/thing/whatever</span>
</pre><br />
<br />
Helicon Ape uses regular expressions to process requests and do the actual redirection at IIS level. Turns out what I needed was to append a $1 (being the first and in this case only parameter to the rewrite expression) to the end of the target URL: -<br />
<br />
<pre><span class="Apple-style-span" style="color: yellow;">RewriteRule ^products/old-category/(.*)$ http://www.mysite.com/products/new-category/$1 [NC,R=301,L]</span>
</pre><br />
Job done. Works nicely :)MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-29782468404227040842010-12-01T21:30:00.000-08:002010-12-01T21:31:49.342-08:00Speeding Up NHibernate Startup TimeThanks to <a href="http://weblogs.asp.net/ricardoperes/archive/2010/03/31/speeding-up-nhibernate-startup-time.aspx">Development With A Dot</a> for this one. Works a treat :)MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-71847823307938042402010-12-01T16:33:00.000-08:002010-12-01T21:31:58.605-08:00jQuery "Live" and ASP.NET AjaxNow as you may be aware, ASP.NET Ajax is a big bloaty beast and I don't like it much. I wouldn't recommend it for a public website taking a zillion hits a day.<br />
<br />
<div></div>However, for knocking together a UI for an intranet app, where you have gallons of network capacity (or is it measured in fathoms, can't remember) and can dictate the browser that will be used, it's not so bad - mainly cos it does a lot for little input. Which I do like.<br />
<br />
<div></div>I have a scenario in an intranet app where I want to show a modal popup after validating certain conditions in server-side code; and within this popup, I want to do some jQuery Ajax.<br />
<br />
<div></div>Following the quick'n'dirty approach, I used an AjaxControlToolkit ModalPopupExtender (no sniggering at the back) to show the popup. All good so far - popup appears and disappears.<br />
<br />
<div></div>Within the popup, I wanted the user to be able to search for products by name & category, and select from a list returned, closing the modal as they do so. Here's the script I was trying to attach: -<br />
<br />
<div></div><pre class="javascript" name="code">$(document).ready(function ()
{
$("#btnSearch").click(function ()
{
$.getJSON("itemSearchHandler.ashx",
{
"categoryID": $("#cboSearchCategory option:selected").val(),
"term": $("#txtSearchProductName").val()
},
handleResult
);
});
// etc
</pre><br />
<div></div>Trouble is, this handler didn't fire, and I should have guessed as to why not, but h/t to <a href="http://www.philliphaydon.com/">Epic Phil</a> for the solution.<br />
<br />
<div></div>The reason the event doesn't fire is because the DOM elements I am trying to reference don't exist when <b>$(document).ready</b> fires. They are dynamically added by ASP.NET Ajax when the Modal is displayed. jQuery tries to attach a handler and gives up when it can't find the element I'm asking to attach my script to - btnSearch - in the DOM.<br />
<br />
<div></div>Fortunately there is a way around this, and that's to use the <b>.live</b> method: -<br />
<br />
<div></div><pre class="javascript" name="code">$(document).ready(function ()
{
$("#btnSearch").live('click', function ()
{
$.getJSON("itemSearchHandler.ashx",
{
"categoryID": $("#cboSearchCategory option:selected").val(),
"term": $("#txtSearchProductName").val()
},
handleResult
);
});
// etc
</pre><br />
<div></div>This will attach a handler to the event for all elements which match the current selector, <a href="http://api.jquery.com/live/">now and in the future</a>.<br />
<br />
<div></div>Handy !<br />
<br />
<div></div>Other thoughts ? <br />
<ul><li>ASP.NET 4's <b>ClientIDMode="static"</b> is a life-saver for working with jQuery</li>
<li>The standard ASP.NET button control refuses to fire a Click event if it's assigned to the Ok or Cancel controls in a ModalPopupExtender. Use a standard html button (<strong>not</strong> an input type="button")</li>
<li>I feel a bit dirty using ASP.NET Ajax as I've railed against it before and rightly so - <a href="http://www.softworkr.com/why-aspnet-ajax-updatepanels-are-dangerous">here</a>, <a href="http://encosia.com/2007/07/11/why-aspnet-ajax-updatepanels-are-dangerous/">here</a> and <a href="http://encosia.com/2008/04/23/why-you-should-not-place-your-whole-site-in-an-updatepanel/">here</a> you go - but as I said, I'm knocking out a fast-turnaround intranet application not an eBay clone</li>
<li>That's enough for now</li>
</ul>MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-73110317772731450302010-11-20T05:14:00.000-08:002010-12-01T21:31:23.692-08:00SiteCore 6.4SiteCore is a great .NET-based CMS.<br />
<br />
I've seen so many CMS's, I'm frankly sick of them. Give me something useful and new. Hello, SiteCore. It's definitely better than Kentico, Umbraco, DotNetPuke, Sharepoint (ok not just a CMS but hey), OBS and even the legendary Pile of Code.<br />
<br />
The Online Marketing Suite is the icing in the cake. I was in an OMS training day a few weeks ago and I thoroughly enjoyed it. Instrument your code; watch the marketing people have orgasms. Great stuff.<br />
<br />
Thing is, the latest version 6.4 is still not going to *properly* support MVC or .NET 4. MVC I'm still out on; yes I know Model-View-Controller is a great pattern, not sure ASP.NET's version is that good though.<br />
<br />
ASP.NET 4 WebForms is superb - please <a href="http://www.asp.net/learn/whitepapers/aspnet4">read this</a> if you're not up to speed on the many new features it offers. Most ASP.NET developers are WebForms based, and MVC is a big paradigm shift for them. I know it allows a greater testing surface, amongst other benefits, but if you're doing your job properly and maybe following an MVP pattern in your web applications, then why switch ?<br />
<br />
I think SiteCore have a fight on their hands; open-source competitors are going to eat into their share if they can't provide up to date development models, and frankly their licensing takes the piss. They want to charge us for staging licenses. Like.. what ??? Get bent guys..<br />
<br />
The real question. Is <a href="http://orchard.codeplex.com/">Orchard</a> the new messiah, or just a very naughty boy ?MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com1tag:blogger.com,1999:blog-4628018184898096417.post-29587931382431228472010-11-08T22:55:00.000-08:002010-12-01T21:31:41.466-08:00nHibernate 3.0 QueryOver - Searching, and Paging at database levelI've been through numerous data-access technologies with .NET - plain old DataReaders & SqlCommands, Code-genned layers around these of various descriptions and varying degrees of horrible, Pile of Code, Typed Datasets, Linq-to-SQL, Lightspeed, LLBLGen Pro, Entity Failwork. <br />
<br />
Of all these, nHibernate 3.0 is definitely one of them. No doubt something better is on the horizon and when it looms into view I might take a look. Until then, this is working well for me.<br />
<br />
In my humble opinion, NH3 is way better than Linq-to-Fail or infact any other model-based ORF (Object-Relational Failfactory).<br />
<ol><li>The fluent style works well; it's nice to use</li>
<li>It's codegen-able like a crazy thing</li>
<li>It's flexible and very extensible</li>
<li>It performs - the generated SQL is lean and exactly what you need, it's measurably faster than L2S or Lightspeed</li>
<li>It isn't Linq-to-SQL </li>
<li>or a cabbage</li>
</ol>NH3 gives us a whole set of functionality missing from 2.1 - functions that wrap typical SQL functions. It also gives us a lot of additional flexibility with lambda's prevalent over magic strings, so refactoring and catching problems at design time is now a doddle.<br />
<br />
That said, I'd like a nicer way of doing multi-field searches; maybe by using an Expression<ICriteria> as a parameter to my search method ? <br />
<br />
Here is my search method, abbreviated so as not to cause boredom: -<br />
<br />
<pre class="csharp" name="code">public IList<customer> CustomerSearch(CustomerSearchCriteria criteria, int pageIndex, int pageSize)
{
IList<customer> list = null;
using (var session = SessionFactory.OpenSession())
{
var query = session.QueryOver<customer>();
if (!string.IsNullOrEmpty(criteria.CustomerName))
{
MatchMode matchMode;
if (criteria.CustomerSearch == CustomerSearchEnum.StartingWith)
{
matchMode = MatchMode.Start;
}
else if ..
// etc
query = query.WhereRestrictionOn(x => x.CustomerName.ToLower()).IsLike(criteria.CustomerName.ToLower(), matchMode);
}
if (criteria.ActiveOnly)
{
query = query.And(x => x.Active == true);
}
if (!string.IsNullOrEmpty(criteria.Address1))
{
query = query.And(x => x.Address1.ToLower().StartsWith(criteria.Address1.ToLower()));
}
// etc
</pre><br />
I'm working on a nicer way of doing this, so stay tuned. That said, the above is fairly readable; I'm just appending additional sections to the WHERE clause where needed.<br />
<br />
Hmm.. Anyway, one thing NH3 gives us is database-level paging using the SQL Server ROW_NUMBER function, which is efficient (much more efficient than selecting the whole set into memory and doing the paging there..).<br />
<br />
<pre class="csharp" name="code">list = query.Skip(pageIndex * pageSize)
.Take(pageSize)
.OrderBy(x => x.CustomerName).Asc()
.List();
</pre><br />
This is nice, except it *only* returns the rows in the page. How do I know how many rows there are in total, so I can set up my pager accordingly ? <br />
<br />
This is easy when done at stored procedure level, as I can just run an additional Count(*) SELECT and return an OUT parameter, all in one hit to the database. Am I going to need two hits here ?<br />
<br />
As it turns out, the CriteriaTransformer has a "TransformToRowCount" method, which does what we need. This does issue one more SQL statement for the count, and it's submitted separately - so two round trips, not ideal.<br />
<br />
<pre class="csharp" name="code">list = query.Skip(pageIndex * pageSize)
.Take(pageSize)
.OrderBy(x => x.CustomerName).Asc()
.List();
int count = CriteriaTransformer.TransformToRowCount(query.UnderlyingCriteria)
.UniqueResult<int>();
</pre><br />
And after <a href="http://groups.google.com/group/nhusers/browse_thread/thread/16c296414aedc09d">reading this</a>, the process has been simplified even further with the addition of an extension method. So the previous example can be re-written as just ..<br />
<br />
<pre class="csharp" name="code">list = query.Skip(pageIndex * pageSize)
.Take(pageSize)
.OrderBy(x => x.CustomerName).Asc()
.List();
int count = query.RowCount();
</pre><br />
Nice ! But still two database hits. There are two ways to fix this: -<br />
<ol><li>Use a transaction</li>
<li>Use a projection</li>
</ol>I'll write some drivel about projections at a later date.<br />
<br />
Toodles.MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com1tag:blogger.com,1999:blog-4628018184898096417.post-51273735592526305642010-11-08T15:28:00.000-08:002010-12-01T21:32:32.474-08:00StructureMap usefulnessYet again I find myself spending literally minutes of my life trying to figure out why something is going wrong, only to find a useful feature of something that could potentially save many more minutes; time better spent writing unit tests, for example, or lolling around the coffee shop talking about stuff.<br />
<br />
Turns out in the end I'd configured the wrong repository name. Dumbass mistake of the kind we all make from time to time, but one of those cases where the wood is clouding the view of the trees in the way woods always seem to.<br />
<br />
I'd done this .. <br />
<br />
<div class="separator" style="clear: both; text-align: left;"><a href="http://3.bp.blogspot.com/_XoUoO9qc9K4/TNiFUS5FHRI/AAAAAAAAABA/18zUszYmwrU/s1600/Untitled.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" px="true" src="http://3.bp.blogspot.com/_XoUoO9qc9K4/TNiFUS5FHRI/AAAAAAAAABA/18zUszYmwrU/s1600/Untitled.png" /></a></div><br />
instead of this..<br />
<br />
<div class="separator" style="clear: both; text-align: left;"><a href="http://4.bp.blogspot.com/_XoUoO9qc9K4/TNiFnc4XV_I/AAAAAAAAABE/Vr6SGFvB73o/s1600/Untitled.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" px="true" src="http://4.bp.blogspot.com/_XoUoO9qc9K4/TNiFnc4XV_I/AAAAAAAAABE/Vr6SGFvB73o/s1600/Untitled.png" /></a></div><br />
Note "EmployeeRepository" instead of "LookupRepository". For clarification, LookupRepository wasn't yet finished. <br />
<br />
Upon trying to resolve a reference to IEmployeeService, StructureMap was throwing Exception code 202 - "No Default Instance defined for PluginFamily IEmployeeRepository". Confusing at first, turns out I was of course staring at the obvious problem all along.<br />
<br />
Trying to replicate this was a pain as it was a case of fire up unit test; get to point that fails; fail (repeat). <br />
<br />
Now I'm sure you've come across the ObjectFactory's "WhatDoIHave" method - which dumps out the state of the container, and what resolves to what. It's a useful way of pinpointing anything that doesn't have a concrete type defined for resolution. However, this chap is even more useful: -<br />
<br />
<div class="separator" style="clear: both; text-align: left;"><a href="http://1.bp.blogspot.com/_XoUoO9qc9K4/TNiG1DHQGRI/AAAAAAAAABI/spFH7L3_NIc/s1600/Untitled.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" px="true" src="http://1.bp.blogspot.com/_XoUoO9qc9K4/TNiG1DHQGRI/AAAAAAAAABI/spFH7L3_NIc/s1600/Untitled.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div style="text-align: left;">Rather than having to get to the GetInstance method of StructureMap to find out you have a configuration problem, you can instead call this after ObjectFactory.Initialize, and it'll run through the map and attempt to construct everything it can. </div><div style="text-align: left;"><br />
</div><div style="text-align: left;">I wouldn't recommend this for production release, but while in build it could save you at least one cup of coffee. And that's a good thing.</div><div style="text-align: left;"><br />
</div><div style="text-align: left;">StructureMap is great. So much nicer to use than Unity. Feeling the love :o)</div>MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0tag:blogger.com,1999:blog-4628018184898096417.post-35311645719319609822010-10-31T15:31:00.000-07:002010-12-01T21:32:42.872-08:00SQL 2008 - Stupid options and sensible practices<a href="http://www.danrigsby.com/blog/index.php/2008/09/26/sql-server-2008-error-saving-changes-is-not-permitted/">http://www.danrigsby.com/blog/index.php/2008/09/26/sql-server-2008-error-saving-changes-is-not-permitted/</a> <br />
H/T to Dan Rigsby for saving me a metric crapload of time. <br />
<br />
Ok I can see the sense, somehow - that option prevents you from saving table changes that require the table to be copied, dropped and re-created with the changes, for example, when changing column nullability.<br />
<br />
But to have this enabled when you're in the thick of the database <em>design and creation </em>process is just bloody annoying. Took me a few expletives raged at the monitor too. Grrr.<br />
<br />
After thinking about this a bit further, it's actually a really stupid option. Anyone making changes to production databases using the table designer should be put up against a wall and shot.<br />
<br />
<strong>Production </strong>databases. These are things that must be updated with extreme caution.<br />
<br />
Scripting is the only way to go. At a push, use SqlCompare if you're lazy, but I've seen that go wrong too.<br />
<br />
Script any and all database changes <em>as you make them in development</em>. Round-table these with the others if you're working in a team. Work out a strategy for updating, migrating data, and so on. <br />
<br />
In other words, do it properly ffs. Database changes are the cause of at least 176% of all production problems and if you and the guys work out a process, you are thinking correctly. If you rely on stupid table designer features to save you from your own stupidity, then you're stupid.<br />
<br />
Thanks for listening.MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com1tag:blogger.com,1999:blog-4628018184898096417.post-20558130104781989032010-10-28T05:48:00.000-07:002010-10-28T05:48:30.421-07:00Blake's 7 is awesome :)<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_XoUoO9qc9K4/TMlwNFtcIXI/AAAAAAAAAA4/Kg4p2YpYIzk/s1600/blakes7gang3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="218" nx="true" src="http://1.bp.blogspot.com/_XoUoO9qc9K4/TMlwNFtcIXI/AAAAAAAAAA4/Kg4p2YpYIzk/s320/blakes7gang3.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div>First technology-related post is<strike> about something to do with .NET</strike> actually no, bollocks. Watched all of the first 3 series of Blake's 7 recently. Well, series 3 is more Avon's 7 but I digress. <br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/_XoUoO9qc9K4/TMlwYi0iY8I/AAAAAAAAAA8/hpC4UKrbDkc/s1600/Blakes%25207%2520Liberator.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" nx="true" src="http://2.bp.blogspot.com/_XoUoO9qc9K4/TMlwYi0iY8I/AAAAAAAAAA8/hpC4UKrbDkc/s320/Blakes%25207%2520Liberator.jpg" width="320" /></a></div><br />
They don't make TV like this any more. Ok so the special effects are awful - models wobbling through the outer reaches of the BBC cleaning supplies cupboard, computers made from Lego, the inside of the Liberator looks like it was bolted together during a drunken after-party at B & Q. Some of the acting is a bit hammy.<br />
<br />
But most of it is great, the stories are superb and it was totally better than Star (urgh) Trek, which did and shall always suck, copiously. I generally hate sci-fi TV shows, but this slice of 70's/early 80's nostalgia was great to relive. I do vaguely remember it as a kid.. had no idea what it was all about of course.<br />
<br />
Next post will be about .NET, promise ;o)MonkeyBoyhttp://www.blogger.com/profile/18348270065028348767noreply@blogger.com0