home · blog · groups · about us · contact us
DevelopmentNow Blog
 Monday, April 07, 2008
 
 

The easiest way I've found involves two steps:

Adjust SSMS Settings

  1. Go to Tools->Options
  2. Query Results->SQL Server->Results to Grid
  3. Check "Include column headers when copying or saving results"
  4. Click OK.
  5. Note that the new settings won't affect any existing Query tabs -- you'll need to open new ones and/or restart SSMS.

Now next time you run a query, do this

  1. Make sure the results are displayed in a grid (CTRL+D or Query->Results To->Results to Grid)
  2. Right click in the grid, and click Select All
  3. Right click in the grid again & click Copy
  4. Open up a new Excel spreadsheet, and paste the data in
  5. Do a global search & replace, replacing "NULL" with an empty string.

Voila!

I had tried before with SSMS's export to CSV feature, and it just didn't escape data the way I needed it to.

April 7, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Friday, March 28, 2008
 
 

So you can probably tell that I've been doing a lot of LINQ lately. :) One thing I've found is that it's easier for me to write complex queries in the database as stored procedures or views, and then use Linq to SQL to retrieve the results, sort, filter, do paging, etc.

The downside of that approach is the results normally come back as a <view or proc name>Result type, instead of the actual table type. That's sometimes an issue, because I use partial classes to give my table classes some extra functionality, and I might want to allow updates, etc. against various tables.

So the goal is to be able to call a view or stored procedure, but coerce those results into a good ol' MyTable object.

You may already know how you can drag a stored procedure or view from your database (in Server Explorer), and drop it on top of a Table entity in the O/R designer. That will cause the stored procedure to return results of that table's type, instead of <procname>Result.

But Rick Strahl had a great post from a while back explaining how you can use views, procs, & dynamic SQL, and cast those results to a specific table type using ExecuteQuery. A snippet from Rick's post is below:

What's also interesting is that when you provide LINQ a query like this it still works with the DataContext's change tracking. For example, the following code actually works as you'd expect:

IEnumerable<Customer> custList =  context11.ExecuteQuery<Customer>("select * from Customers where CustomerId={0}", "ALFKI");
Customer cust11 = custList.Single<Customer>();
Response.Write(cust11.CompanyName); 
cust11.CompanyName = "Alfreds Futterkiste " + DateTime.Now.ToString();
context11.SubmitChanges(); 

custList = context11.ExecuteQuery<Customer>("select * from Customers where CustomerId={0}", "ALFKI");
cust11 = custList.Single<Customer>();
Response.Write(cust11.CompanyName);

The cool thing (as Rick mentions) is that you don't have to do a "select * from Customers" -- you could do a "select CompanyName, ContactName from Customers" and it will work, too. You don't need to bring back all columns in order to successfully cast the result to a Customer object.

I'll post my continuing forays into Linq as I continue. One thing that remains to be seen is whether Linq to SQL is robust enough to be helpful vs requiring me to extend it too much to do what I want/need.

March 28, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Thursday, March 27, 2008
 
 

Yeah so this isn't brand new. But the jQuery Cheat Sheet is for version 1.2, at least. Visual jQuery (which I still use a lot) is only for jQuery 1.1. I sure hope someone doesn't come out with a Visual jQuery clone for jQuery 1.2.X ... :)

March 27, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 
 

I wanted to put up a few examples of SQL vs Linq to SQL for my future reference, since we're using it in one of our social media projects for artists. I'm pretty handy at SQL, but it doesn't translate exactly to Linq to SQL.

Example 1

Assume you have a view called vev_bws_mediaVoteDownloadHistory that votes and downloads for different media by date. So it contains columns like mediaId, artistId, activityDate, votes, and downloads.

If we wanted to query this view to get the total number of votes and downloads for a given media, you could use SQL like this

SELECT 
    votes = SUM(votes),
    downloads = SUM(downloads)
FROM vev_bws_mediaVoteDownloadHistory WHERE mediaId = 12345

Or use Linq to SQL like this

veDataContext dc = new veDataContext();

var totals = (from v in dc.vev_bws_mediaVoteDownloadHistories
              where v.mediaId.Equals(12345)
              group v by v.mediaId into h
              select new
              {
                  votes = h.Sum(x => x.votes),
                  downloads = h.Sum(x => x.downloads)
              }).FirstOrDefault();
if (totals == null) then return; // no totals

Response.Write(totals.downloads);
Response.Write(totals.votes);

Example 2

So the first example was jsut getting a few simple sums. Here's a bit more complex example.

Assume you have a view called vev_bws_userMediaHistory that logs votes for a given artist and his/her media. The view fields like votes, artistName, mediaName, userId (the user who cast the vote), and voteDate (a datetime column storing the date & time of a vote).

So since voteDate contains dates and times, I want to display all the votes grouped by media, artist, and date (not time). I could use SQL like this:

SELECT 
    votesperday = SUM(votes), 
    date = CAST(FLOOR(CAST(voteDate as FLOAT)) AS DATETIME),
    mediaName,
    artistName
FROM vev_bws_userMediaHistory
WHERE userId=1
GROUP BY 
    CAST(FLOOR(CAST(voteDate as FLOAT)) AS DATETIME),
    mediaName,
    artistName
ORDER BY CAST(FLOOR(CAST(voteDate as FLOAT)) AS DATETIME) DESC

Note that the CAST/FLOOR/CAST trick is used to trim off the time from a datetime, leaving just the date portion. This allows us to sum up votes cast throughout the day into a "votes per day" value.

To do this in Linq to SQL I would use this:

veDataContext dc = new veDataContext();

var votes = (from v in dc.vev_bws_userMediaHistories
             where v.userId.Equals(1)
             group v by new 
             { 
                 v.voteDate.Date, 
                 v.artistName, 
                 v.mediaName
             } 
             into h
             orderby h.Key.Date descending
             select new
             {
                 date = h.Key.Date,
                 artistName = h.Key.artistName,
                 mediaName = h.Key.mediaName,
                 votesperday = h.Sum(x => x.votes)
             });

The above Linq select statement allows me to reference the artistName in my ListView via <%# Eval("artistName") %>. If I had instead used this select statement

select new
{
    h.Key,
    votesperday = h.Sum(x => x.votes)
}

I would need to use something like <%# Eval("Key.artistName") %> instead.

March 27, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 
 

FYI, there's a bug in the RTM LinqDataSource where child tables aren't loaded unless you have updating or deleting enabled. Apparently if you have a LinqDataSource that doesn't have updates or deleted enabled, ObjectTracking is turned off (for performance reason), but deferred queries (e.g. queries to pull back child rows) aren't executed.

So statements like

<%# Eval("ChildTable.ChildTableField") %>

in your ListView, etc. won't work.

Annoying, needless to say. But at least now I know.

So, there are a few options:

  1. Set EnableUpdate="true", which will enable ObjectTracking and cause deferred updates to work
  2. Add a SELECT statement in your LinqDataSource (e.g. SELECT="new (field1, field2, childTable)") to pull back everything you need.
  3. Handle the ContextCreated event to either manually set ObjectTrackingEnabled, or manually set LoadOptions.
public void OnContextCreated(object sender, LinqDataSourceContextEventArgs e) {
  ((DataContext)e.ObjectInstance).ObjectTrackingEnabled = true;
} 

OR 

public void OnContextCreated(object sender, LinqDataSourceContextEventArgs e) {
    var dataLoadOptions = new DataLoadOptions();
    dataLoadOptions.LoadWith<MyTable>(t => t.ChildTable);
    ((DataContext)e.ObjectInstance).LoadOptions = dataLoadOptions;
}

Setting LoadOptions is normally the best approach for performance.

March 27, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Friday, March 21, 2008
 
 

It's time for web-centric coffee again ... The Portland Open Coffee Club is meeting next Wednesday, 10am, at Pier Coffee (600 NW Naito Parkway, near Glisan & 3rd). Pictures below -- Pier Coffee is a quiet, open coffee house with free wifi and a central location. Stumptown is awesome but I think it's starting to be a bit small & loud for the growing POCC crowd.

What is Portland Open Coffee Club? Well, it's a laid-back, casual gathering for people interested in startups, the web, or technology to talk, network, and meet like-minded people. Read more at http://www.opencoffeeclub.org/

POCC event page on Upcoming: http://upcoming.yahoo.com/event/174640/

P.S. Mark your calendars for Aril 10th, 5pm, at Baileys for Portland Open Beer Club. POBC is the same as POCC, just in the evening with beer instead of morning coffee.

March 21, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Thursday, March 20, 2008
 
 

I noticed an interesting post from Allison Beckwith about Project Planning Grids. She also provided links to Todd Warfel's Task Analysis Grid and Blink Interactive's Objects & Actions Analysis. All three posts centered around different grid styles & focuses, but they all discussed ways to map out the different objects/features of a project in an easy-to-understand grid, so that you can flesh out requirements, standardize vocabulary, and understand which items need to be developed when.

Allison & Todd's grids felt higher-level, and included color & position to denote schedule & priority. Blink Interactive's grid was more detailed & was perhaps a better way to ensure you didn't miss a requirement. I could perhaps see starting with Blink's grid to round out your featureset, and then a grid like Allison or Todd's for planning & priority.

At DevelopmentNow we do a lot of project work, so one of the first things we do is map out a project featureset into "chunks" and rough feature descriptions, then assemble them into a basic dependency & delivery list. One of the big aspects in project management is getting scope right, and since there's always a tradeoff between delivery time & overall features, it's important to make sure that you haven't forgotten a critical feature, and that everyone (including and especially the client) understands what will be delivered when. So I can see how the additional dimensions in a grid, along with colors, can help add additional contextual scope information without sacrificing simplicity.

FYI, Todd actually prints out his grids on huge (like 6 feet wide) paper, puts them up on a wall, and talks through them with clients, allowing the client to write on the paper, interact with it, etc.

Some sample screenshots of grids below:

 

March 20, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Wednesday, March 12, 2008
 
 

I wanted to announce that the first meeting of Portand Open Beer Club will be Thursday, tomorrow night, at Bailey's Taproom in downtown Portland at 5pm.

Portland Open Beer Club is the same format as Portland Open Coffee Club. People interested in web, tech, or startups get together for a laid-back, agenda-free gathering, so that entrepreneurs and developers can chat, network, and grow. The main differences with Portland Open Beer Club is that:

  1. It's Beer instead of Coffee
  2. It at 5pm instead of 10am

Event link: http://upcoming.yahoo.com/event/450110/

Feel free to swing by, have a pint, & say hello! Of course, you don't have to drink anything to attend, and Bailey's has a number of other beverages and small plates available. We'll also probably be having Mexican food delivered there, in case anyone's in the mood for dinner.

March 12, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Thursday, March 06, 2008
 
 

Well, you can't really "roll back" commits per se, since Subversion remembers everything you've committed. But, if you realize that your current version of a file or directory is bad, and you need to restore that to a previous version number, you can do a svn copy like this

svn copy --revision 7  http://svn.yourdomain.com/svn/trunk/somefolder/myfile.php ./myfile.php

The above command will pull down myfile.php from version 7 of your repository and place it into your working copy. You can then check it in with

svn commit ./myfile.php -m 'rolled back to version 7'
You can also roll back directories instead of just specific files.
March 6, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]



 Tuesday, March 04, 2008
 
 

Office Live Workspace, the online document collaboration service from Microsoft, is now out of closed beta. It allows you to share and edit Office documents with others over the web, control permissions, and other online collaboration features. It also supports Firefox 2 on Mac OS X. You need Office to actually edit the documents (since editing occurs offline), but anyone with a browser can view and comment on the docs.

I've been using Google Docs for over a year now, and while it works decently, I sometimes miss the advanced features from Office, and it can be slow at times. I tried out Office Live Workspace this morning, and it definitely let me keep my desktop app experience. In fact, it felt mostly like WebDAV, albeit a slicker, better, easier-to-use version. Which isn't necessarily a bad thing, as long as all your editors have Office installed.

There's a web portion that lets me preview documents, and invite others to view and/or edit them. There's also an Office add-in that I installed, which added "Save To Office Live" and "Open From Office Live" to all my Office programs, allowing me to interact with the service. I was pleased to see that Offie Live stores the revisions of your documents across changes, but I didn't see a way to compare revisions. You can get email notifications of when someone edits documents, but there's no RSS feed. Anyone with a browse can comment on documents, but all the comments are just stacked on the right-hand side -- you can't position a comment over a particular item in the document.

I'm looking forward to when Live Documents comes out of closed beta, because that service will allow you to edit documents online, or using Microsoft Office or Open Office.

So, Office Live Workspace isn't bad. If everyone involved is a Microsoft Office user, it's definitely better than emailing documents back and forth. And you do get the full power of your desktop apps when managing documents, which is a big plus for power users or less web-savvy users. And since you can view and comment on documents using a browser, even non-Office users can contribute to a small degree. But the lack of online editing and robust features mean that upcoming services like Live Documents pose a real threat as the web world gets more cross platform and online only.

You can view more some screenshots of Office Live Workspace here.

 

March 4, 2008    Bookmark to Digg or other social bookmarking
#    Disclaimer  |  Comments [0]