27 February, 2008

LINQ to SQL: SQLMetal.exe

I have recently switched over to using SQLMetal to generate my LINQ-to-SQL DBML and Context class. There are two things I like about it, one is that it is far faster. I just click a script on my desktop rather than open up the designer and recreate each table that has changed. I also prefer some of its naming conventions, it deals with multiple relationships to a  single table better.
Consider the case where you have an Orders table and it has two fields holding Address keys (ie ShippingAddressID and InvoiceAddressID). The LINQ-to-SQL generator in Visual Studio will create 4 properties ShippingAddressID,  InvoiceAddressID, Address, Address1. The last two being references to the Address entities. The problem being you cant work out which is which.
SQLMetal will detect this and one of them will be named ShippingAddress, sadly the other will still be simply Address. There is hope though.
SQLMetal.exe is a pretty straightforward console application that is installed alongside Visual Studio and can be used to generate your classes for you. For more details check out MSDN.
Creating your classes is a two step process, I have a .bat file on my desktop to do it for me.
cd /d "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin"
SqlMetal /server:.\SQLEXPRESS /database:AdventureWorks /dbml:<DBML File>
SqlMetal /code:<Class File> <DBML File>
Note: There are a number of other options you will want to investigate at the link above.
The other nice thing about this, though I have not investigated it yet, is that you get a hook on the DBML file before it is used to create the class file. This means if you wanted to you could run it through an XSLT processor with a stylesheet that defines all the changes you want to make to the data model. This gives you a great way of abstracting your changes away from the base model and saves you the time and hassle of making the every time you update the model. If I actually take the step of doing this I will be sure to blog about it with an example. One change you may want to consider is fixing the above issue of the double links being poorly named.

17 February, 2008

YUI - Yahoo! UI Library

I am spending the weekend getting to know a bit more about the Yahoo! User Interface Library.
You can find more details yourself here http://developer.yahoo.com/yui/

They do a good summary on their site, so let me start by simply quoting Yahoo!

The Yahoo! User Interface (YUI) Library is a set of utilities and controls, written in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources. All components in the YUI Library have been released as open source under a BSD license and are free for all uses.

There are a couple of really neat things about this library that I will quickly run through to see if I can grab your attention.

First and foremost for any HTML/CSS developers out there, YUI provides 3 core CSS files: Reset, Core and Fonts. These are fundamentally important to anyone working on websites in my opinion.
Reset removes all in-built styling, from every browser. Right down to removing the bullets from <li> and the bold from <em>. It provides an utterly blank canvas for you to start styling from.
Core then applies the usual formatting you would expect each tag to have, only it does so in a way that is consistent between all browsers. As any web developer should know, not all tags look the same between different browsers.
Fonts will apply a standard set of font-families across al browsers and platforms to give you the best chance of getting the font you are after.

If you look at nothing else in the YUI library, you should still check out the Reset and Base CSS files. They are applicable to every single website you will create and will remove a lot of headaches with cross browser interfaces.

Other CSS goodies include a set of tools for creating consistent Grid layouts (2-column, 3-column, 4-column etc) and a default skin for their UI components. I haven't gone looking yet, but I am sure there are more skins floating around the net, or you can create your own.

Next we have a large collection of javascript files that work together to provides layers of useful support from basic helper functions, AJAX calls, simple UI controls all the way up to DataTables, ImageLoaders and all sorts of things.
This library is so rich you are better off looking through their examples than having me try explain them to you. The key here is that everything is built and tested to work across a wide range of browsers and platforms without you needing to know all the CSS hacks to make it work. Anyone looking to build a modern UI on a website would be served well to see what these guys are up to.

The third feature of YUI that I find quite interesting is that Yahoo! offers free hosting of all the JS and CSS files used. Including past versions. In fact they give you the links (and more importantly permission) to link into the exact same data farm that serves these file to their own production websites. Needless to say this reduces bandwidth on your own site, and comes with some good caching and compression at their end. If you can trust an external source to host a couple of your files, this is worth taking a look at.

That's it for now, I am still learning my way through the library myself. If I come across any cool tips of features I will be sure to pop up a post later. In the end I may use nothing but the Reset and Base CSS files from the library, time will tell.

15 February, 2008

Useful Extension Method for IEnumerable

I have written a useful (in my opinion) Extension Method for the IEnumerable<> objects used in LINQ that I will share in this post.

I call it CastAs() and it basically performs a casting operation on every item in a collection, returning a second collection of the results.

The LINQ classes ship with a Cast() function that will work if the compiler knows how to cast between the two objects, but in the cases that it does not this one will help you out.

Note: I avoided calling the method Cast() as Intellisense did not like it and hid the original Cast() method even though they had different signatures.

Now for the function.

public static List<T2> CastAs<T1,T2>(this IEnumerable<T1> list, Func<T1, T2> fn)
{
    List<T2> list2 = new List<T2>();
    foreach (T1 item in list)
    {
        list2.Add(fn(item));
    }
    return list2;
}

I am currently returning a List as this has been the form I wanted the results in every time I have used it so far. Feel free to make your own decision on a return type however. You might even be able to make its return type anonymous, though I had no luck trying that.

The function takes a single parameter which is a Lambda Expression representing a function mapping the first type to the second type. Here is an example converting a List<string> into a List<int>.

List<string> x = new List<string>();
x.Add("1"); x.Add("2"); x.Add("5");
List<int> y = x.CastAs(s => Int32.Parse(s));

Trivial, but useful.

However a place you might find this more useful is when dealing with Many-to-Many joins in LINQ-to-SQL. Sadly the modelling leaves a little to be desired.
Imagine you have two tables Users and Roles. Then you have a Many-to-Many table joining the two called UserRoles. In LINQ-to-SQL an instance of a User record will have a collection of UserRole's attached to it, where as what you really want is a collection the Roles themselves. Well using our above function you can do just that with a single line of code.

List<Role> roles = myUser.UserRoles.CastAs(d => d.Role);

The lambda expression tells the function how to "cast" each UserRole into the Role on the other side of the join.

Note: This does not have any neat mapping into SQL on the server side for performance help, so if you were to run this against a full table you would bring back a lot of data and do a lot of processing on the client. So think first before you use this. Using the DataContext.LoadOptions.LoadWith() function would help if performance was a concern.

In case anyone takes offence to my calling this a cast, I don't mind if you choose to implement the function with a more "correct" name.

13 February, 2008

LINQ to SQL: Be careful of CreateDatabase()

I have recently started work on what will become our first production application using LINQ-to-SQL and had hoped to use the CreateDatabase() function that is found on the generated DataContext to simplify the process of setting up the database on the client machine.
Ideally I wanted a nice simple piece of code like this
AdventureWorksDataContext db = new AdventureWorksDataContext();
if (!db.DatabaseExists())
{
    db.CreateDatabase();
}
At first glance this works great, you get a shiny new database created with all the right tables and relationships. The devil however is in the detail.
Because LINQ-to-SQL only models the database relationships, some important information is not stored in the DataContext and therefore will not propagate with a CreateDatabase() call. This includes (but is not limited to) Default Field Values and Triggers.
Now it is possible to code around this. If you like, both can be handled in code by hooking into the OnValidate() partial method of your generated data classes. See here for a previous post about partial methods, though not specifically that method.
However the next problem is not so easy to code around. Although a relationship such as FK_OrderItems_Orders will be created in your new database, it will not necessarily have the same name as the relationship in your master database. In fact the two don't even follow the same naming standard (LINQ-to-SQL leaves out the FK_) so they are almost certain not to have the same name.
What this means is that you can not write a SQL script against the master database to be rolled out onto the client databases with a future upgrade.
Sadly this renders the CreateDatabase() call basically useless in anything other than the simplest applications.
I would love to see LINQ-to-SQL in the future ship with a set of tools that wrapped up proper database creation and upgrades for you and could reduce it to a piece of code as simple as that above. Now that would be pretty special.