October 31, 2012

Windows Phone 8 SDK is out!

I really, really need a Windows 8 phone right now. It is the creeping uneasiness that only a gadget junkie can understand.

I also need a 3d-printer, some new Win8-tablets and a .Net Gadgeteer. I also need the time to play around with them. Hey, I hardly have time to blog these days.

Most of the positive talk regarding Windows Phone 8 has been about the shared core with Windows 8, that you finally can use it on decent hardware and that you now have THREE different sizes of tiles instead of  a meager two.

The negative talk touched the fact that those who bought 7.5 phones can forget the possibility to upgrade them to version 8.

They are dinosaurs, soon extinct.

The thing I find most interesting in 8 is something else, the Company Hub and the new ways of deploying apps for companies who don't want their apps to be hanging on the Marketplace.

For you that might not sound so impressive.

For me it means that I can finally have a slight hope of working with coding Windows Phone 8 apps to customers.

Windows Phone is a much more interesting alternative for enterprise customers than to end customers (read: releasing stuff on the marketplace) as long as the market shares are the way they are. (Why release an app to 1.7% of all smart phone users instead of 50%?)

So if some company wants to use a mobile as an internal tool, I believe Windows Phone 8 could be a strong competitor right away. And maybe, maybe that could give me the chance to start developing WP8-apps outside of my apartment.
After all, there is so much more time at work than home.

Oh yeah... If you would like to start coding you can find the SDK here!

August 28, 2012

A generic way to read data from an SqlDataReader

Through the years I have been struggling to find a really good way to read data from a datareader. If you know me, you also know that I prefer good old reliable methods that puts me in control to object relational mapping..

Consider the following code (didn't compile it so forgive me for eventual bugs):



    private static List<Book> ReadData(string connectionString)
    {
        List<Book> books = new List<Books>();
        string queryString =
            "SELECT Author, Title, Year FROM Books";

        using (SqlConnection connection =
                   new SqlConnection(connectionString))
        {
            SqlCommand command =
                new SqlCommand(queryString, connection);
            connection.Open();

            SqlDataReader reader = command.ExecuteReader();

            while (reader.Read())
            {
                Book book = new Book();
                book.Author = reader("Book");
                book.Title= reader("Title");
                book.Year= reader("Year");
                books.Add(book);
            }

            reader.Close();
            return books;
        }
    }
}

This code should work pretty well, the problem comes when you start using nullables. If year were int? instead of int this code this would throw an exception as soon as a null value appears in the reader.

Null in Sql Server and in c# are two different things.
From the database points of view a field has three values:

  1. A value. For example 1993.
  2. A null value. We left the year empty because we didn't know the year.
  3. Empty, the book does not exist.
Now you might argue that if the row was empty a try would anyway give you an error and the pragmatical side of me totally agrees, but still, the issue stems from the fact that null in C# is the absence of a reference to an object, while null in a database is an uninitialized or empty value. It exists and we have to deal with it.

I like solving this with extension methods (actually I am generally pretty hooked on extension methods).

The standard approach is to use something like this:

public static int? ToNullableInt(this int value)
{
    return value.IsNull ? (int?) null : value.Value;
}

And then call the reader like:

book.Year= reader("Year").ToNullableInt();

It is a reasonable solution. But you would have to write those extension methods for every nullable data type.

A single function version that handles all data types plus basic conversion but also is slightly slower looks something like this:

           private static T Get<T>(this SqlDataReader reader, string index, T defaultValue = default(T))
          {
                    var t = reader[index];
                    if (t == DBNull.Value)
                                return defaultValue;
                   Type type = typeof(T);
                   if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                   {
                               var subType = Nullable.GetUnderlyingType(type);
                               return (T)Convert.ChangeType(t, subType);
                   }
                   return (T)System.Convert.ChangeType(t, typeof(T));
           }

This would be called like this:

book.Year= reader.Get<int?>("Year");

When microseconds are not the issue, I prefer that solution, but I am always looking for something even better. Ideas? :)



August 1, 2012

My populator is beginning to take shape

I have been knee deep into my populate project the last days and I truly believes that meta programming is somewhat like LSD. It seriously fucks up your mind.

When you take a step away from your usual garbage in - garbage out project and enter the realm of reflection and generics stuff can be, well, abstract.

I hopefully will finish the project before ending up in an asylum.

In the meanwhile I am happy to see that there will be a Build conference this year. Read all about it here.

I went to the conference last year and loved it, will definitely take a talk with my boss about this one. So far there is no more info than that the registration will start at 8, the 8th day in month 8. Why are developers so beautifully nerdy? :)

Now back into the code again! See you!

July 18, 2012

Just to prove my theory...

In my last entry I made a Shakespeare generator.

I completed it with a Strindberg generator:


Som det!
Fiskar utanför ett ord.
Att följa mig från vita skjortbröstet och vila; fyllde i sin levnads mål, ingen annan sak till fånga och jag är bittert ibland med god dag?
Varpå ett tyst och lämnade Arvid Falk tittar jag säger oss, men nu svarade Sellén.
Ty hans brustna moln av utlänningen, tyst att han!
Låt mig!
Och vad har lossnat här, är gudfruktig!
Varför han så finns välgörenhet också!
Hennes nåd skulle komma hit utan ser jag tala, i Byggmästarbanken.
När di kommer visst inte känner sig böjd att Sellén, här har du opp.
Nu har du fått slag.
Men han uttalade alltid; den tog upp.
Stod Ygberg såg huru skulle fosterlandets namn; befann sig på vår begravningsbön.
Konglig sekter o den ena lakanet blivit snillen, att han sin överrock med en stol skjutas på en gumma, Karlen super ju värden höjde första revbenet.
Nåå!
Denne sköt hela sin motståndares argumenter.

And a Goethe generator:


Benutz es hinkte, höchster Herr ich schnell quillt, dem ich weiß, so wird nicht, folge ziehn die Gift?
Als sonst kamt ihr anständig seh' ich, der Geist verwirrt genug, Echo!
Zwar ist sie zu schauen aus millionen kehlen.
Da steigen meine Widersacher drängen, ich bei den erdball abgeründet, dem seeisch heitern feste Unzugängliche Mauer spaltet sich ganz ausgewachsen schauen, die Füße tragen; aber hüte dich auf!
Fackeln, die Kraft, Hiebei darfst du nichts an das Proszenium.
Nun fort, uns im dienen, wir?
Du scheinest mir doch gar selten aber flammt's empor und solch einen!
Begnügen sollt' ich allen Seiten hundert Hügeln unterbrochner Fläche fließt Peneios: auf!
Und Land, sie sich ergetzten, wir sehn!
Der flammend sich die thronen hehr, Umstellend ruhigen Friedensweiher.
Durchlauchtigster, angebaut.
Die Neigung, gemein!
Den Mittelpunkt.
Der schönsten einer längst gewohnt der Ernte zu dem heiligen liebeshort.
Ein Schnippchen schlagen deine macht erst sah sie genießen wollten, ein Marmorblock als er sich selbst außer mir den klügsten Mann, schlachterzogne junge Brut?
Ich nicht benommen; Fuß nimmt jeder, Chiron könntest du's doch gewandter sein, entflammte stroh.
Sind gewohnt, hier ja mein, wie das Papiergespenst der Treppe, so sehr es am besten frommt; über der einzig vom meinem Geiste.

Was considering a Bukowski generator, but I foresaw the results...

Lightning storms in Sweden when I write this.

July 8, 2012

The Shakespeare Generator


A fool thinks himself to be wise, but a wise man knows himself to be a fool.

I didn't write that. Shakespeare did. Wish I had though.

For us with an ounce less talent but with a will to cut corners I decided to make a Shakespeare generator.

So what is the Shakespeare algorithm?

I don't know, but I can show you my take on the subject.

The easiest way would of course to just randomize the words. In the example above you could get stuff like:
"A think a to himself."
Or
"be knows a to a"

Definitely words from the Shakespeare vocabulary, but still crappy. You will not find any memorable quotes there unless you randomize a lot. A lot like in this.

If I were a linguist I would try the other end of the spectrum. I would analyze each word and implement the grammatic rules on when and how to bend them.

For me that sounds too tiresome. I want quick results.

So I constructed a graph out of Macbeth.

The basic fact was that Macbeth is made out of sentences and the sentences are made out of words.
All sentences has a start and an end, made out of an ending sign such as "?", ".", "!". To make it easier for me I decided that "," ";" and ":" also ends a sentence. After all it is word groups rather than pure sentences that I am seeking.

So the graph starts with a start node and that node is connected to all words that starts a sentence, namely "a" and "but".


And then I just continued adding nodes for each word to the following word. Eg. "A" -> "Fool", "Fool" to "Thinks" etc. 

When a word came to an ending sign, I added a link to a node of that sign, such as "Wise" -> "," and "Fool" -> "."

When a word came up that already had a node, I didn't add a new node, but just a new edge, so the "Wise" node is connected both from "Be" and from "A". 

When the same word pair came up a second time, such as the double connection between "A" and "Fool", I added a one to the weight of the edge, ending up with a weighted graph.

I did this for the complete Macbeth which means that a word such as "A" is connected to 119 other words with different weights depending on how often those words shows up.

When my graph is ready I can randomize a trip through it from start node to an end node. Randomized based on the weight of the edges. Wise huh? This pseudorandomization also sees to that words usually have the correct ending and that all words fit with the word before it.

So some generated sentences:


Mingle with you make us.
Come to the subject of our chimneys were a ring the gate make such welcome.
Whey-face?
Every man.
Madam, 
and blind-worm's sting, 
I' the honest men our offices and 'tis the instruments, 
at peace?


"Come to the subjects of our chimneys" Poetry!

Next step will be to make a graph consisting of all Shakespeares works.

Am I wise or not? (or just a simple fool)

PS. The graph was made using this tool. Recommended!

July 5, 2012

Generate word like sentences

Randomizing data is fun so I decided to make a program to automatically fill objects with data.
i started out with totally random data, but I realized that 'lhghhjfdr' is not that fun to put as value in a string so I have been producing generators.

Generators that can do the Lorem ipsum, generate random names, superhero names, street names, titles, cities... and generating random stuff started to be fun again.

One thing I wanted to do was to generate word like words, strings that have no meaning but are easy to read and pronounce.  Pseudo random text.
I found this and it gave me a basic algorithm, I spiced it up with this to give each letter a statistical weight.

The random word is made of a random number of parts that are concatenated. The parts are either v, cv or cvc where c stands for a consonant and v stands for a vocal. which part type I choose is of course random.

The probability for each letter is according to the letter frequency in the english language:


private void LoadLetters()
{
Vowels = new List<WeightedLetter>();
Consonants = new List<WeightedLetter>();
Vowels.Add(new WeightedLetter() { Letter = 'a', Weight = 81 });
Vowels.Add(new WeightedLetter() { Letter = 'e', Weight = 127 });
Vowels.Add(new WeightedLetter() { Letter = 'i', Weight = 70 });
Vowels.Add(new WeightedLetter() { Letter = 'o', Weight = 75 });
Vowels.Add(new WeightedLetter() { Letter = 'u', Weight = 28 });
Consonants.Add(new WeightedLetter() { Letter = 'b', Weight = 15 });
Consonants.Add(new WeightedLetter() { Letter = 'c', Weight = 28 });
Consonants.Add(new WeightedLetter() { Letter = 'd', Weight = 43 });
Consonants.Add(new WeightedLetter() { Letter = 'f', Weight = 23 });
Consonants.Add(new WeightedLetter() { Letter = 'g', Weight = 20 });
Consonants.Add(new WeightedLetter() { Letter = 'h', Weight = 60 });
Consonants.Add(new WeightedLetter() { Letter = 'j', Weight = 2 });
Consonants.Add(new WeightedLetter() { Letter = 'k', Weight = 7 });
Consonants.Add(new WeightedLetter() { Letter = 'l', Weight = 40 });
Consonants.Add(new WeightedLetter() { Letter = 'm', Weight = 25 });
Consonants.Add(new WeightedLetter() { Letter = 'n', Weight = 67 });
Consonants.Add(new WeightedLetter() { Letter = 'p', Weight = 19 });
Consonants.Add(new WeightedLetter() { Letter = 'q', Weight = 1 });
Consonants.Add(new WeightedLetter() { Letter = 'r', Weight = 60 });
Consonants.Add(new WeightedLetter() { Letter = 's', Weight = 63 });
Consonants.Add(new WeightedLetter() { Letter = 't', Weight = 90 });
Consonants.Add(new WeightedLetter() { Letter = 'v', Weight = 10 });
Consonants.Add(new WeightedLetter() { Letter = 'w', Weight = 24 });
Consonants.Add(new WeightedLetter() { Letter = 'x', Weight = 2 });
Consonants.Add(new WeightedLetter() { Letter = 'y', Weight = 20 });
Consonants.Add(new WeightedLetter() { Letter = 'z', Weight = 1 });
}


Choosing parts:



private static string GeneratePart()
{
int PartTypeChoose = GeneratorData.Instance.Randomizer.Next(8);
if (PartTypeChoose == 0) //less single vovels
//v
{
return  GeneratorData.Instance.GetWeightedLetter(GeneratorData.Instance.Vowels);
}
else if (PartTypeChoose < 4) //3 out of 8 seems good
//cv
return GeneratorData.Instance.GetWeightedLetter(GeneratorData.Instance.Consonants) + 
                                            GeneratorData.Instance.GetWeightedLetter(GeneratorData.Instance.Vowels);
else 
//cvc
return GeneratorData.Instance.GetWeightedLetter(GeneratorData.Instance.Consonants) + 
                                            GeneratorData.Instance.GetWeightedLetter(GeneratorData.Instance.Vowels) + 
                                            GeneratorData.Instance.GetWeightedLetter(GeneratorData.Instance.Consonants);
}

Creating some text returns this:

hix ridholo nilroclel ananlu lishavho sehehef casho tiba tendutose senoset tevsehro atota rignu getil hamoko votrof riheu deta oa reue sorfartim rocdino atehhi sesraw mit etos wereh ret teqe moletoh tata e hecladi dadug lepxu dehdon hey tifoi usencaw bi hepnis ita hemeleyna nohni wahi coyitif xor nahtan sohaa wenora no sateto tapef larnemacag tiyco cagsa yer husra ta fa

Isn't it beautiful?

June 24, 2012

Windows Phone 8, will it finally make it?

I have been waiting for the version 8 of my favorite mobile OS and now when they showed it my feelings are a bit mixed. The main thing that stirs up my feelings is that you cannot upgrade a 7.5 telephone to Windows 8.
I didn't expect this from Microsoft. The early rumors where hinting that you would be able to upgrade your Lumia to the new OS. On the other hand, with a bit retrospective and with the talk of using parts of the Windows 8 kernel in the phones, I should have guessed.

This will on the other hand give me an edge in the ever ongoing "who has the coolest phone in the office"-competition, their Lumias will only make it to 7.8...

Every cloud has a silver lining...

So for the truly good news?

Version 8 finally gets a chance to compete with other smartphones when you just check the hardware specs.

It gets the multi-core processor, high resolution screens, true multitasking, integrated skype, offline maps.  The best and in my point of view, a critical must for the success of Windows on the phone is that it will share code with Windows 8. In effect this will mean that Microsoft is choosing one road for all its devices. It is Windows 8 from phone to Server. This also gives me confidence that Microsoft will not to as they do with Windows Phone 8 again, namely cut off their existing user base.
This seems like a long term strategic choice and even though it has a slightly bitter aftertaste it still is needed in the long run.

So will there be a long run?

I still believe that Windows 8 will make it. It simply has features that makes it so much more powerful than the iPad or the Android tablets. It is a real computer. And I believe that Windows 8 will be the beast that will pull the Windows phone.

I hope so.

Windows Phone 8 is just too sexy to disappear. Just look at those nice square things on the screen!


June 18, 2012

Philosophy, technology, religion

Sometimes programmers are strange, actually most of the time programmers are strange.

Me included.

And maybe this is just my twisted and over-simplified view on the subject, but I see a clear line between the developer with a philosophical view on the subject and those with a more technological take on it.

It is a division that can be seen all the way from the universities split in educations for system sciences and those for software engineers.

Philosophers seeks the best way to split reality into parts, engineers tries to make the best parts to resemble the world. Top-down and bottom-up. People that are specialized in abstracting and those that are experts in coding.



Both sides are needed, but problem's arise when coders forget that that is a fact and adopt a one way minded view of the subject, often with an almost religous conviction.

Give programmers a buzzword and they will follow.

The technological religions seems to dominate right now. Most of the new methods and patterns results in a bottom up approach to development. An alluring belief that following a path can create the perfect system.

There are definitely religious philosophers too, an architect colleague to me once said that "when you construct a system, the most important is to be as flexible as possible and you achieve maximum flexibility by not constructing anything.".

The scary part was that he meant it.

The good thing, that he eventually got fired.

I went to a (for me too short) seminar with Chris Klug about the problems with the Test Driven Development (TDD) paradigm and got inspired.

TDD has a religious following in that the users seem to believe that every project gets better if you follow it strictly, the code gets better and the solution gets better. Use tests everywhere and you will see the light.

Lately, I have heard the same opinions about a lot of technologies and methods and if I look back I have heard the same statements before about older technologies. Some people seem to believe that the solution of all problems in the world lies in a three letter acronym.

CQRS, TDD, Scrum, ORM, Functional programming, Object orientation, SOA, Sql, NoSql, Open Source...

There are grains and sometimes tons of truth in all methods, but in my world they are just pieces in the big jigsaw puzzle. Use it, but don't be a Taliban.

Each tool has its place and a time when it should be forgotten.

The goal is to make a good system not to use a certain method or technology.

No method will do the work for you.

Amen...

June 7, 2012

A small break

Recording music with ÜNF this week, so no updates in the blog.

Will try to do some coding this weekend.

May 31, 2012

Spatiality Part 4, Fiddling with SQL Server Spatial SQL

SQL Server is quite potent when it comes to spatial queries. It follows the Open Geospatial Consortium Simple Features for SQL, Version 1.1 and implements about 70 functions covering areas such as intersects, unions and the like. Basic GIS-stuff.

It is a bit different syntax from what most people are used to, but once you get past that it's a breeze.

SQL Server 2008 supports two kinds of spatial data.

Geometry, that means flat.
Geography, that means spherical.
I still believe that the world is spherical even though I read a lot of hard evidence suggesting otherwise here. 


So I would choose the geography style. However, all my data is flat so...


In my spatial database I have lots and lots of areas. And it would be nice to get all areas within say 20 km from my position. (I can't believe some third world countries still hang on to miles)


You can probably do this the hard way and use a lot of math to get an answer, or you can do it the GIS way.


GIS (Geographical Information Systems) is a neat science. One of its strengths is to get new information by making calculations on thematic layers on a map. For me it started with reading the book Map Algebra by Dana Tomlin and I was hooked. If you are interested read more here.


Spatial SQL is a bit different but you can achieve a lot by using similar techniques.

Back to the task.


My plan is as follows:
  1. Create a geographical area covering a 20 km circle with it's center in the middle of stockholm.
  2. Use that circle to overlay my data and by SQL return all the objects that intersects my buffer.
  3. Show it in my blog.
Let's start with number one in the list.

DECLARE @stockholm geometry = geometry::STPointFromText('POINT (18.06861 59.32944)', 4326)

So... what do we do here? We (or actually I) create a point geometry by using the geometry::STPointFromText function. As parameter we have the coordinates as a string followed by the mystical 4326 which simply points out that we are using the reference system WGS84. The same reference system as my own data.

This will give us a one dimensional point.


To make it into a circle we use:

DECLARE @stockholmbuffer geometry = @stockholm.STBuffer(0.2)

We simply tell SQL Server to make a buffer around our point with the distance 0.2. 

The distance on my map is in degrees. Lats and longs. 

And a degree is around 110 km and 20% of that is just close enough 20 km to make me happy. 
I'm not picky.

So now we have declared a 20ish km radius circle with its center in Stockholm.

Next step is to overlay it with the existing data.

This is how we do it:


SELECT *
FROM areas
WHERE ogr_geometry.STIntersects(@stockholmbuffer) = 1

Just a simple call to the intersect function that returns 1 on an overlap.


So to summarize:


DECLARE @stockholm geometry = geometry::STPointFromText('POINT (18.06861 59.32944)', 4326)


DECLARE @stockholmbuffer geometry = @stockholm.STBuffer(0.2)


SELECT *
FROM areas
WHERE ogr_geometry.STIntersects(@stockholmbuffer) = 1

And the result is this:






May 24, 2012

Spatiality (a short interlude with a hint of bitterness)

Importing data to SQL Server needs its own entry in this blog. Especially when it comes to international characters. You know: 'Ö', 'Ü', 'Ñ',  and the likes. I am talking about UTF-8, UTF-16 and other ways to map a character to bits and bytes.

Character encoding.

The problems started in 1963 with ASCII (and probably earlier in the analog world with Morse codes, viking runes and smoke signals). ASCII and IBM's ECBDIC managed to fit a character into seven and eight bits respectively. Memory space was a very limited resource those days so all was good until someone realized that there actually exists other languages than English and they tried to hack it into ASCII using ISO 8859.

This time they forgot small regions such as the Arabic world, Japan, India and China...

1988 they finally started working on UNICODE and nowadays we only have one way to save international characters: UTF-8, UTF-16 and UTF-32...

Most stuff you find on Internet is UTF-8, SQL Server handles UTF-16 and when you import stuff into the database without spending an hour of googling ahead of the task everything ends up in the non UTF fields called varchar...

Some people probably love code pages and character encodings. I don't. For me it is one of those totally uninteresting side issues that distracts my creativity from really achieving something. It is fully in the line with issues such as coordinate transformations, spending time fixing web stuff to make it readable in any browser and trying to access web services not made for Microsoftians as myself.

I hate it.

Give me one type of coordinate, browser, service and one type of string!

I want to use my brain for content and functionality, not details.

So... this long rambling obviously cooks down to the fact that I goofed up and managed to import all that data in spatiality 3 to a varchar field instead of an nvarchar field. And as I have a blog I have the opportunity to channel my bitterness...

Getting the stuff all the way to Azure made it even less interesting to go through the whole process again and try to import the data 'the right way'.

So I googled.

Ye who google shall find.


I found this. A function that fixed my mistakes and saved a good day of work for me. I just added an nvarchar to the table, updated it with the function and dropped the old one. Worked like a charm.

I love google and I love people like Jason that cleans up after my mistakes. Thank you!



May 12, 2012

Spatiality Part 3

Finally, after a barrage of work, I have the possibility to do some own coding and make one more step toward finishing my next app.

So... were are we?

In part 2 I finally managed to export a shape file to Sql Server 2008, this time I plan to export that spatial data to my Azure SQL.

So what to do when you start with something you never done before?

Google!

My first finding was this link. Since I enjoy simplicity the Import and Export Wizard sounded perfect. I've used it countless times before and it has never failed me.

I follow the steps, opens up an ip address to azure and everything works brilliant until I get to the Review Data Type Mapping phase, when the wizard gives me something like this:


Reason? The Import and Export Wizard can't export spatial datatypes...

So time to google again!

This time I found the SQL Azure Migration Wizard.

This tool has a bit of crappy GUI (I use the 125% size on text and it doesn't handle it). But i transfers data using Bcp so I had least hope of getting it to work.

My first attempt crashed, another googling and I realized that I needed to upgrade my SQL Server to service pack 1.

I tried again and this time:



I ran  a query agains the table in SQL Server Management Studio and lo and behold, all is there!

Next up: exposing the data through an azure web service.

PS. If you like sharepoint follow this!

May 9, 2012

Another don't in SQL Server...

Found out the hard way that it's not a good idea to rename your default data base in SQL Server 2005 (yeah, some of us still work with ancient technology).

If you do, you will be stuck for some time googling and guessing sqlcmd commands. More info here.

May 3, 2012

Spatiality Part 2

As I almost promised in part 1, I got my hands dirty in converting shape files to SQL Server.
It wasn't as easy as I hoped.
I started out by downloading the source code for GDAL at http://www.gdal.org/ and tried my C++ skills. 

They were not too impressive.

After failing to build the project I started googling for "ogr2ogr binaries" and found some windows binaries here.

I unpacked the zipfile, navigated to the apps folder and tried ogr2ogr.exe. Of course it didn't work. It complained that it couldn't find the gdal19.dll file. 

I found that file in the bin catalogue, copied ogr2ogr.exe to the same directory and tried again.

Finally a response.

Trying out the full ogr2ogr command for my shape file and SQL Server was up next.

ogr2ogr -overwrite -f MSSQLSpatial "MSSQL:server=[my server name];database=[my database name];trusted_connection=yes" "[my shape file]"

Of course it complained of more missing files. This time it missed the gcs.csv file. 
I found it in the gdal-data folder and copied all of the folders content to the bin folder and tried again and voilá! 160000 objects imported into SQL Server like magic. Pretty quick too.

Maybe I was a bit drastic in copying files like a maniac, but hey, it worked! And now I can just type 

SELECT TOP 500 name, ogr_geometry FROM areas

Resulting in this in SQL Server (I love the spatial results tab):



May 1, 2012

Spatiality Part 1

I have an old love affair with large data sets. It really feels cool to have a database over ALL birds in the world, a network graph of all connecting flights in the world or detailed data over all the countries in the world.

When I was nine or ten years old all I wanted for Christmas was Statistisk Årsbok.

I got it. I loved it.

My bookshelves contains a plethora of different non fiction titles chosen to pick every subject possible. I got books on medieval weapons, about steam machines, gardening and tropical diseases.
I don't know why I am so fascinated on the thought of collecting all the world's data but I do suspect that collecting is one of the reasons. Another reason is probably the pursue of knowledge. A third the sense of having control over the world. The rest probably comes from my childhood, they say that most stuff originates from it. Mine was good.
Even better than data sets are data sets with a position. Maps. They say that 95% of all information can be positioned. I don't know if it's true, but I used it as a fact when I was teaching Geographic Information Systems(GIS) at the university.

GIS can be a troublesome experience for a developer. The main players are huge systems that not always are easy to develop in. If you ever tried coding in AML or MapBasic you know what I mean.
Maps, how easy they may seem, are complicated beasts and in a GIS system you add data layer by layer usually from different sources. Land data from one place, vegetation from another, roads from a third and so on. Each source can be of a different cartographic projection and level of detail meaning that your aggregated map very well can end up with roads in the ocean and country borders that overlap. I really hate cartographic projections by the way. It is old technique when you had to map the round world onto a flat paper. Let the world be round in a computer! Projections just makes it more complex and I want my life simple.  (I guess that is one reason why I love Google Earth)

Since version 2008 you can also put maps into  SQL Server, which opens up new hacking possibilities that I am eager to explore. The problem, however, is that most of the map data out there is in a different format.
The industry standard in map data is the Shape File used in ArcGIS, nowadays in competition with KMZ used by Google.

SQL Server supports none of these.

What's worse, I haven't really found any easy free way to import data. I installed GeoKettle after first having to learn how to install a .jar file with adminstrator rights. When I finally got it started, I didn't really understand it. I just want to import some data and I don't want a GUI that is more complex than choosing a source and a destination. I checked out FME, which is good but not free, but they can just read from SQL Server Spatial data. I need to write. I finally ended up with OGR2OGR from GDAL, which means using the good old DOS prompt instead of same fancy GUI. Not a simple solution (I even had to compile it myself) but I guess I'll just have to try it as soon as my huge data set comes in. This link made it seem promising. So hopefully I will soon control the world! :)

April 25, 2012

How to get to Norway.

Bing is cool! (at least the map part)

I loaded up Visual Studio and fixed a developer key at www.bingmapsportal.com and then I spent an hour hacking with the Bing web services for routes.

I wanted to create an easy function to get directions from coordinate A to coordinate B and I wanted it to be asynchronous. Oh, yeah, I didn't care much about performance or any other details, just wanted results. After all a hack is a hack.

So. This is how I did it. Step by step.

1. Get a key to bing maps.


3. Created a route class with the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MapTools.BingRouteReference;

namespace MapTools
{
public class Routes
{
public delegate void RouteCompletedHandler(object sender, RouteFinishedEventArgs e);

public event RouteCompletedHandler RouteCompleted;

public void Calculate(Location start, Location end)
{
BingRouteReference.RouteServiceClient routeService = new
                                            BingRouteReference.RouteServiceClient();

RouteRequest routeRequest = new RouteRequest();
routeRequest.Credentials = new Credentials();
routeRequest.Credentials.ApplicationId = "[put your map key here!]";

routeRequest.Waypoints = new Waypoint[2];
routeRequest.Waypoints[0] = new Waypoint();
routeRequest.Waypoints[1] = new Waypoint();
routeRequest.Waypoints[0].Location = start;
routeRequest.Waypoints[1].Location = end;

routeService.CalculateRouteCompleted += new 
                                         EventHandler<CalculateRouteCompletedEventArgs>      
                                         (routeService_CalculateRouteCompleted);

routeService.CalculateRouteAsync(routeRequest);
}

void routeService_CalculateRouteCompleted(object sender,  
                                        CalculateRouteCompletedEventArgs e)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (var item in e.Result.Result.Legs.SelectMany(s=>s.Itinerary) )
{
stringBuilder.AppendLine(item.Text);
}
RouteFinishedEventArgs eventArgs = new RouteFinishedEventArgs()
                                     {RouteDescription = stringBuilder.ToString()};
RouteCompleted(this, eventArgs);
}
}
public class RouteFinishedEventArgs
{
public string RouteDescription { get; set; }
}
}

4. Created a client (winform is still quicker for trying out hacks):

Routes routes = new Routes();

public FormTester()
{
InitializeComponent();
routes.RouteCompleted += new 
                                Routes.RouteCompletedHandler(routes_RouteCompleted);
}
private void buttonExecute_Click(object sender, EventArgs e)
{
                        //Stockholm to Oslo
routes.Calculate(
                                new MapTools.BingRouteReference.Location() 
                                { Latitude = 59.32944, Longitude = 18.06861 },
                                new MapTools.BingRouteReference.Location() 
                                { Latitude = 59.94944, Longitude = 10.75639 });
}

void routes_RouteCompleted(object sender, RouteFinishedEventArgs e)
{
textBoxResults.Text = e.RouteDescription;
}

5. Sat back and enjoyed the directions:

<VirtualEarth:Action>Depart</VirtualEarth:Action> <VirtualEarth:RoadName>Gustav Adolfs Torg</VirtualEarth:RoadName> toward <VirtualEarth:Toward>Malmtorgsgatan</VirtualEarth:Toward>
<VirtualEarth:Action>Bear</VirtualEarth:Action> <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>Norrbro</VirtualEarth:RoadName>
<VirtualEarth:Action>Turn</VirtualEarth:Action> <VirtualEarth:TurnDir>left</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>Slottskajen</VirtualEarth:RoadName>
<VirtualEarth:Action>Bear</VirtualEarth:Action> <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>Skeppsbron</VirtualEarth:RoadName>
<VirtualEarth:Action>Road name changes</VirtualEarth:Action> to <VirtualEarth:RoadName>Södermalmstorg</VirtualEarth:RoadName>
<VirtualEarth:Action>Road name changes</VirtualEarth:Action> to <VirtualEarth:RoadName>Västra Slussgatan</VirtualEarth:RoadName>
<VirtualEarth:Action>Road name changes</VirtualEarth:Action> to <VirtualEarth:RoadName>Hornsgatan</VirtualEarth:RoadName>
<VirtualEarth:Action>Bear</VirtualEarth:Action> <VirtualEarth:TurnDir>left</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>Långholmsgatan</VirtualEarth:RoadName>
<VirtualEarth:Action>Road name changes</VirtualEarth:Action> to <VirtualEarth:RoadName>Liljeholmsbron</VirtualEarth:RoadName>
<VirtualEarth:Action>Road name changes</VirtualEarth:Action> to <VirtualEarth:RoadName>Södertäljevägen</VirtualEarth:RoadName>
At exit <VirtualEarth:ExitNumber>Södertäljevägen</VirtualEarth:ExitNumber>, <VirtualEarth:Action>take</VirtualEarth:Action> ramp <VirtualEarth:TurnDir>left</VirtualEarth:TurnDir> for <VirtualEarth:RoadName>E20 / E4</VirtualEarth:RoadName> toward <VirtualEarth:Sign>Helsingborg / Göteborg</VirtualEarth:Sign>
At exit <VirtualEarth:ExitNumber>Trafikplats Saltskog östra</VirtualEarth:ExitNumber>, <VirtualEarth:Action>take</VirtualEarth:Action> ramp <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> for <VirtualEarth:RoadName>E20</VirtualEarth:RoadName> toward <VirtualEarth:Sign>Strängnäs / Södertälje C / Göteborg</VirtualEarth:Sign>
<VirtualEarth:Action>At roundabout</VirtualEarth:Action>, <VirtualEarth:Action>take</VirtualEarth:Action> <VirtualEarth:ExitNumber>1st</VirtualEarth:ExitNumber> exit
At exit <VirtualEarth:ExitNumber>Trafikplats Gräsnäs</VirtualEarth:ExitNumber>, <VirtualEarth:Action>take</VirtualEarth:Action> ramp <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> for <VirtualEarth:RoadName>E18 / 249 / E20</VirtualEarth:RoadName> toward <VirtualEarth:Sign>Örebro / Göteborg / Lindesberg / Oslo</VirtualEarth:Sign>
At exit <VirtualEarth:ExitNumber>110A</VirtualEarth:ExitNumber>, <VirtualEarth:Action>take</VirtualEarth:Action> ramp <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> for <VirtualEarth:RoadName>E18</VirtualEarth:RoadName> toward <VirtualEarth:Sign>Örebro flygplats / Karlskoga / Oslo</VirtualEarth:Sign>
<VirtualEarth:Action>Pass through 2 roundabouts</VirtualEarth:Action>, remaining on <VirtualEarth:RoadName>Örebrovägen</VirtualEarth:RoadName>
<VirtualEarth:Action>At roundabout</VirtualEarth:Action>, <VirtualEarth:Action>take</VirtualEarth:Action> <VirtualEarth:ExitNumber>2nd</VirtualEarth:ExitNumber> exit onto <VirtualEarth:RoadName>E18 / E45</VirtualEarth:RoadName>
<VirtualEarth:Action>Keep</VirtualEarth:Action> <VirtualEarth:TurnDir>straight</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>E18 / Orrhagen</VirtualEarth:RoadName>
<VirtualEarth:Action>Pass through 4 roundabouts</VirtualEarth:Action>, remaining on <VirtualEarth:RoadName>Trøgstadveien</VirtualEarth:RoadName>
At exit <VirtualEarth:ExitNumber>Vinterbrokrysset</VirtualEarth:ExitNumber>, <VirtualEarth:Action>take</VirtualEarth:Action> ramp <VirtualEarth:TurnDir>left</VirtualEarth:TurnDir> for <VirtualEarth:RoadName>E6</VirtualEarth:RoadName> toward <VirtualEarth:Sign>Oslo</VirtualEarth:Sign>
<VirtualEarth:Action>Keep</VirtualEarth:Action> <VirtualEarth:TurnDir>straight</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>E6</VirtualEarth:RoadName>
<VirtualEarth:Action>Road name changes</VirtualEarth:Action> to <VirtualEarth:RoadName>150 / Hjalmar Brantings Vei / Ring 3</VirtualEarth:RoadName>
<VirtualEarth:Action>Take</VirtualEarth:Action> ramp <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> toward <VirtualEarth:Sign>Tåsen / Maridalen</VirtualEarth:Sign>
<VirtualEarth:Action>At roundabout</VirtualEarth:Action>, <VirtualEarth:Action>take</VirtualEarth:Action> <VirtualEarth:ExitNumber>2nd</VirtualEarth:ExitNumber> exit onto <VirtualEarth:RoadName>Rolf Wickstrøms Vei</VirtualEarth:RoadName>
<VirtualEarth:Action>At roundabout</VirtualEarth:Action>, <VirtualEarth:Action>take</VirtualEarth:Action> <VirtualEarth:ExitNumber>1st</VirtualEarth:ExitNumber> exit onto <VirtualEarth:RoadName>Maridalsveien</VirtualEarth:RoadName>
<VirtualEarth:Action>Turn</VirtualEarth:Action> <VirtualEarth:TurnDir>right</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>Blåsbortveien</VirtualEarth:RoadName>
<VirtualEarth:Action>Turn</VirtualEarth:Action> <VirtualEarth:TurnDir>left</VirtualEarth:TurnDir> onto <VirtualEarth:RoadName>Ustvedts Vei</VirtualEarth:RoadName>
<VirtualEarth:Action>Arrive</VirtualEarth:Action> at <VirtualEarth:WaypointName>Ustvedts Vei</VirtualEarth:WaypointName>

So now you know how to get to Norway...

PS. Just let me know if you want the full code.

April 21, 2012

My top ten list on how to succeed with large projects. (1)

Do not forget the customer

Customers pay for your fun job, they know the problem area much better than you do and they share an interest with you to make a good program. Do not forget them!

In an ideal world customers should be as entwined in the project as the developers, project managers, architects... For some reason there is usually a need to fight with them a bit to make them a part of the project. Try telling them that the project costs so many millions and that without the know how for a comparatively small cost the project might fail. 

The project needs the customer. Their involvement brings so many vital benefits and very few hazards. You minimize the risk that you will discover that you misunderstood what the system was supposed to do after a few months, you solve problem areas much quicker and you have nicer coffee breaks. 

The customer on the other hand will hopefully start to understand the fabric of your work and he will be reassured to see that you are not only taking coffee breaks all of the time. At least not without him.

April 20, 2012

My top ten list on how to succeed with large projects. (2)

Keep expectations where they should be

There are many pitfalls when time estimating or promising features. You may be overly enthusiastic and get swept away by the enthusiasm, you may believe too much in your own abilities, you are afraid to tell the customer the real costs, you simplify the impact of the uncertainties and risks in the project or you simply forget about all the boring stuff that needs to find time as well such as testing, documentation, meetings...

There is a saying that you should multiply your estimates with pi, but I don't buy that. Better to learn how to estimate correctly and to know when not to estimate than to just tell the customer that the project will cost three times as much as you believe. In the end no one will be happy if the project gets delayed.

Honesty is a good trait. If you cant make an estimate say so. And try to keep your hybris and megalomania pinned down, so common traits among developers. After all we are a bit like gods, being able to create anything we can imagine in the virtual world called a computer.

April 19, 2012

My top ten list on how to succeed with large projects. (3)

Industrialize!

Sometimes it seems like it's rude not to include everyone in all parts of the project resulting in a development method where every developer is part of the process from GUI down to the database and the external services. 

Software development is at the same level as how cars were produced before the T-Ford. They are built by hand, painstakingly, and they still end up with quality flaws that would have been corrected with a more industrial approach.

Software development methods are of course getting better, but still membership in a project is something that puts developers in a position where they are supposed to work eight hours a day from the start until the end of the project. It matters less if they are the best for the current task or not, yet in a project there are some highly specialized tasks that needs specialized skills like usability design, deployment, graphic design, performance testing etc.
How many of you haven't seen a good developer spending weeks on making lousy graphic design, buttons and the like? (For some reason few people seem to have strong skills in design and programming at the same time)

On the other end of the spectra we have projects where you appoint a manager or an architect even though you know that his or hers commitment is limited in time or effort. Putting an architect for the first months only in a big project will only damage it. Leading roles in a project should be long term.

So how do we get to a point where we can industrialize the process of making software?

I think that one important step is to sell more solutions than resources to the customer. If you sell a consultant for six months to a customer, he will stay there. If you sell a solution that will take six months to complete you will have a freedom in the staffing and you have at least a possibility to put the right person at the right task. Another important step is to have simple rules of thumb on staffing a project always striving to put the right person on the right spot with the right level of commitment.


April 18, 2012

My top ten list on how to succeed with large projects. (4)

Responsibility makes better software

Last entry on this list concerned losing control over the project, this one shares the subject. Having control is a key to not only manage and finish a high quality project in time, it is also vital for the developers ability to sleep at night. 
So who's fault is it if something goes wrong? If the database ends up without normalization and the business layer turns up as a huge mass of code with ugly dependencies in every direction. 
In many projects that is a question that no one can answer. "It just grew out to be like this" or "we had so little time" are common and sometimes valid excuses.

I believe in responsibility. I believe that someone should be responsible for the structure in the database, in the business layer, the unit testing and that everyone follows the GUI guidelines of the project.

The reason for this is not because I like to punish people, the reason is that issues have a tendency to fall between people, to disappear and gather dust. This can to some extent be removed with clear responsibilities. If this is my area I want it to be as good as possible, that would at least be my instinct.

I wouldn't want to be caught up with tables without primary keys in my database and I sure as hell would want my business entity to be as easy to manage as possible, something that is best achieved by doing it right.

Responsibility makes better software.

April 17, 2012

My top ten list on how to succeed with large projects. (5)

If you lose the map you're lost

Have you ever been in a project where the developers lost the big picture? It is tough to get back from.

If the map, the architectural blueprints, are lost it is like a disease out of control. The quality goes quickly from so-so to non-existing. People begin to duplicate code instead of using existing mechanisms, they put methods in other classes than they logically belong to and the cohesion gets more and more strongly coupled when the developers skip the architecture and shoots from the hip. And with bad code, unhappy coders.

The software architecture is more than just how the system was envisioned once in the beginning of the project. 

It is a guideline that should be kept alive throughout the project. It is the language of the project.

The architecture should continually be communicated throughout the project. A social gathering just as important as the scrum meetings or the project meetings. Focus on what should be where and how to reuse existing code. Focus on black box issues, code discussions beyond the classes and their interfaces are less helpful. As a developer I don't really care how a method is constructed as long as it accepts the arguments I want to change and do what I want it to do. Don't get stuck in details. I have seen too many projects where the  discussions is more about using tabs or spaces for indenting than entities. 

So to summarize: I propose an overview of the architecture every monday morning at 09:00! Keep the map alive!

April 16, 2012

My top ten list on how to succeed with large projects. (6)

Demand a TCO for system architectures.

Do you remember TCO? It stands for Total Cost of Ownership and was common in the nineties for corporation calculating the total cost of their computer and software investments. The calculus should not only include the initial cost of stuff, but also costs for management, licences, infrastructure, education, salaries etc. 
I believe it is time to take this paradigm to system architectures.
Architects and developers are usually geeks with an interest in their job. They like programming. 

And they also like everything that is new and hot and they are very curious about trying stuff. 

Stuff that stays interesting for a month or so until the next new cool stuff shows up.

Stuff that ends up deep in the architecture of the systems they create. 

Stuff that in the end can cost the customer a lot of money and what is bad for the customer is bad for the developers. (even if it can give them a longer project in the short term)

I don't mean that you never should adapt new programming paradigms, add third party libraries or use new patterns to build the software. System development is about evolution, otherwise we might all just stay programming COBOL.

I do however mean that you should think before you do it.

Think in terms of "How much do I gain by using this new stuff?", "How much will it cost?", "How much more complex will the code get?", "Can we find developers that know this stuff or will people make shortcuts and further degrade the architecture?", "Will this new stuff be legacy in a few years or will it stay?". "Do we really, really need this?", "Which are the alternatives?"

In short make a quick TCO-analysis. Don't just buy the buzz words without thinking.

April 13, 2012

My top ten list on how to succeed with large projects. (7)

#7 Scrum slowly in the beginning.

I really like scrum or other agile methods, but I am not one of the religious fanatics. Scrum like any method has its strengths and weaknesses. Scrum is time boxed and is focused on dividing a task into smaller subtasks that can be given time estimates. It is an effective method when the domain is well known. The focus on what instead of how can however be a problem when making the system analysis. It is all too easy to forget that you cannot build a system without taking time to make up a lasting architecture, simple enough to be understood and rich enough to cater for the whole system, not just for a sprint. Although agile methods have mechanisms for system analysis, it just doesn't seem like a first citizen. Agile methods are focusing on keeping the work and produced code up, not for taking it slow and think. But no thinking makes a stupid system architecture.
Don't do until you know what to.

System architectural decisions early in a projects lifetime are decisions that lives for a long time and are hard to change. It can be mistakes that will cost many, many hours.

So use scrum, but take it slow in the beginning. Make time for some thinking.

April 12, 2012

My top ten list on how to succeed with large projects. (8)

#8 Cut up the cake

Have you also been in a project where you afterwards said stuff like "yeah, we should have done it in smaller pieces" or "I don't understand the system anymore"?

Software systems are like tigers, they start all cuddly and sweet but suddenly you have a 1000 pound man-eater in your office. And once you lose control over the beast it takes lots of effort to regain it.
The bigger the system the harder to control, but somehow, even though we all know about the importance of using modules when coding, it is easy that the system gets to big to understand.
Modularized code is almost as old as programming itself, but to use it you need to think before you start coding and you need to continue thinking while you add new functionality. 

Common sense, right?

April 11, 2012

My top ten list on how to succeed with large projects. (9)

#9 Isolate

For me succeeding with a project is to reach high quality and stay within budget. To be able to take responsibility for any time schedules and to be able to reasonably well give a good guesstimate on how long  time a project will take you need to know what you are calculating on.

You can never calculate time for external projects. Still most software systems don't live on their own, they have dependencies to external systems, systems that can be unstable, changing or not even constructed yet.

It is a problem. A problem that can be yours if you don't handle it.

If you isolate your software and never make demands of any other functionality than that contained in your system it shouldn't be a problem. But in real life system borders can be unclear and vague and if you don't code for isolation it can be hopeless to see where a problem spurs from.

Some tips:

  • Keep your own data carriers. Loosely coupled code are tenfold more important when working with external components.
  • Build for robustness. Treat all external services as unreliable and always code with that in mind.
  • External frameworks and components can be nice, but they also makes your system more depending on external systems. Think twice.

April 10, 2012

My top ten list on how to succeed with large project (10)s.

#10 Treat the requirement document as an evidence in an upcoming murder trial. With you as accused.

Sellers are sellers and they will always be sellers. Their job is to land deals, sell in stuff and in many cases get a fat provision for doing so. There is a small gap between selling and delivering a solution.
That responsibility lays on the project manager and below him, the system architect and the developers. To add to the problem more and more projects sells for a fixed or semifixed price, risking to give the development crew an impossible task at an impossible price.

What will be constructed is specified in the requirement document. If you want a cv that will not scare away your future employers (because the risk is that you will get sacked when a fixed price project takes a year too long at a cost of x millions) you need to treat this document with utmost respect, because if shit hits the fan this document may prove to be your executioner or your saviour. 
Fuzzy requirements will be the foundation for a fuzzy system and I am not talking fuzzy logic here. Responsibility is a dangerous beast, best treated with respect.

When the project lands on your lap after the seller sugarcoated it, it is up to you to make sure that no work is started without clear requirements. The first job in a project with fuzzy requirements should be to sharpen the specifications, no matter if it is done with analysis, prototyping or with customer workshops. Fixed prices should not be negotiated until customer and consultant agrees in a sufficient detailed way what is going to be built. 

The same rules applies when building the system, beware of gliding requirements or demands that are not specified in the requirement document. You are promising to fulfill whats in this document and you are obliged to make the customer take the consequences as soon as he wants functionality that's not included in this document. 

Of course it goes without saying that accepting a requirement document when you know it lacks vital functionality that the customer will have to pay for later is both unprofessional and unethical. 

You will not keep customers by backstabbing them.

Common sense. Only do when you know what to. 
Wonder why common sense is such a rare commodity. Maybe it has something to do with money.

April 9, 2012

Next project starting

A year ago I released uBirder on the windows phone market. An app for birders, giving them possibility to list all species in a specific area, make observations and get information about bird species. I have been thinking a lot about making a second version on it and today I feel the ideas are mature enough to start working. The plan is to make public webservices hosted on azure and to also release clients for the windows phone and windows 8. I will try to publish glimpses of the work on the blog. (I guess I will be tied up with the project for half a year or something)

But now! Time to create the database! (of course with the help of .CreateSchema)

April 6, 2012

Create Schema 1.0.2 out

I just fixed a few bugs and put a new version of CreateSchema out here. It should fix the relations from generic lists as well as giving a more normalized view of unary relations.

The future is here!

Look at this!
In 20 years people will look back at it and see it as an important stepping stone in the process of turning us all into cyborgs. Microsoft, where are you???? :)

The logic behind the .CreateSchema extension

As I stated earlier, the modelling of a class hierarchy to tables is a lot about guessing. So which guesses do the CreateSchema extension make?

Datatypes

The extension tries to follow the mapping on this page. But of course, since one C# data type maps to several data types in sql server guesses are made. Strings for example maps to nVarChar(8000) and decimal maps to Decimal and not to Money in SQL server. You will have to check the source code for a full list.

Failures

Stuff that the CreateSchema cant handle will end up in the comment field in the bottom of the generated script.

IDs 

Every table gets an primary key column named ID of either Int with Identity or GUID depending on settings, the default is Int with Identity. If you are into other name standards or want other fields acting as keys you will have to edit the SQL. Even relational tables get an ID for a primary key, not the more common way of having an aggregate key consisting of the primary keys of the related tables.

Collections

Every collection of value types or the supported reference types will be broken out into a new table with an ID and a Value field of the type of the collection. The extension currently only do this for generic lists (List<>) so if you have dictionaries or arrays for example they will end up on the failure list. 

Relations

There is no way to really know how to translate relations into tables, there is no semantic notions in c# whether a list of objects symbolize a one to many relation or a many to many relation. I am currently only making many to many relations when there are list of objects pointing from each direction to each other. Eg. object A has a list of object B and object B has a list of object A. 

Enums

Enums are currently broken out to a table much like the collections.

Class hierarchies

I support two ways to map class hierarchies to tables. I either keep class hierarchies and let tables generated by subclasses have all the fields of the superclass, duplicating the data or I split the hierarchies letting the tables generated by subclasses only contain their own properties along with a foreign key to the super class. The default strategy is to split hierarchies.

April 5, 2012

A little hack to simplify my coding...

I am in the beta testing phase of my .CreateSchema-extension, but I still found the guts to put it on CodePlex.

So what is it and how does it work?

Well let's start with a sample object diagram, let us say that you are doing software for a travel company (since this seems to be the standard practice project in swedish universities).

Your object diagram could look somewhat like this:
You got the typical customer with a link to itself and a subclass with a discount, you got a company object that can be either a cruise company, an airline or a charter company. The companies offers travels and one or several persons can write some contracts with some travels. Basic stuff! :)

So now the model is roughly finished and you need to get it into SQL server for persistance. That would mean some few hours of more or less non-creative work, mostly copying properties from c# to SQL Server. Boring, boring job... So (fanfare) enter the CreateSchema extension found here. And then you simply add a reference to the ObjectScriptingExtensions.dll, add a using ObjectScriptingExtensions; to your code and write: 
Traveller traveller = new Traveller();
string s = traveller.CreateSchema();
The string returned by the CreateSchema() will be a long SQL statement that looks like this:

/****** Object:  Table [dbo].[Traveller]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Traveller]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[FirstName] NVARCHAR(4000) NULL,
[LastName] NVARCHAR(4000) NULL,
[FullAdress] NVARCHAR(4000) NULL,
[Telephone] NVARCHAR(4000) NULL,
[Age] INT NOT NULL,
[FKAssociatedTravellers] INT NOT NULL

)

GO
/****** Object:  Table [dbo].[Contract]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Contract]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[ContractReference] UNIQUEIDENTIFIER NOT NULL,
[FKItems] INT NOT NULL

)

GO
/****** Object:  Table [dbo].[ContractItem]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ContractItem]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[Price] DECIMAL(18,2) NOT NULL,
[PurchaseDate] DATETIME NOT NULL,
[Duration] TIME NOT NULL,
[FKPurchasedTravel] INT NOT NULL

)

GO
/****** Object:  Table [dbo].[Travel]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Travel]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[Destination] NVARCHAR(4000) NULL,
[BasePrice] DECIMAL(18,2) NOT NULL,
[FKCompany] INT NOT NULL

)

GO
/****** Object:  Table [dbo].[Company]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Company]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[Name] NVARCHAR(4000) NULL,
[OrganisationNumber] NVARCHAR(4000) NULL

)

GO
/****** Object:  Table [dbo].[CruiseCompany]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[CruiseCompany]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[FKCompany] INT NOT NULL FOREIGN KEY REFERENCES [Company]([ID]),
[FKSeasWithOfferedCruises] INT NOT NULL

)

GO
/****** Object:  Table [dbo].[CruiseCompany_SeasWithOfferedCruises]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[CruiseCompany_SeasWithOfferedCruises]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[Value] NVARCHAR(4000) NULL

)

GO
/****** Object:  Table [dbo].[CharterCompany]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[CharterCompany]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[FKCompany] INT NOT NULL FOREIGN KEY REFERENCES [Company]([ID]),
[FKTypeOfCharter] INT NOT NULL

)

GO
/****** Object:  Table [dbo].[CharterType]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[CharterType]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[Name] NVARCHAR(4000) NULL

)

GO
/****** Object:  Table [dbo].[AirlineCompany]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[AirlineCompany]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[FKCompany] INT NOT NULL FOREIGN KEY REFERENCES [Company]([ID]),
[MajorHub] NVARCHAR(4000) NULL

)

GO
/****** Object:  Table [dbo].[VipTraveller]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[VipTraveller]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[FKTraveller] INT NOT NULL FOREIGN KEY REFERENCES [Traveller]([ID]),
[Discount] REAL NOT NULL

)

GO
/****** Object:  Table [dbo].[Contract_Traveller]    Script Date: 2012-04-05 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Contract_Traveller]
(
[ID] INT IDENTITY NOT NULL PRIMARY KEY,
[FKTraveller_Contract] INT NOT NULL,
[FKContract_Traveller] INT NOT NULL

)

GO

/****** Object:  ForeignKey [Contract_Traveller_Contract_Contract_Traveller_FKTraveller_Contract]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[Contract_Traveller]  WITH CHECK ADD  CONSTRAINT [Contract_Traveller_Contract_Contract_Traveller_FKTraveller_Contract] FOREIGN KEY([FKTraveller_Contract])
REFERENCES [dbo].[Contract] ([ID])
GO
ALTER TABLE[dbo].[Contract_Traveller] CHECK CONSTRAINT [Contract_Traveller_Contract_Contract_Traveller_FKTraveller_Contract]
GO
/****** Object:  ForeignKey [Contract_Traveller_Traveller_Contract_Traveller_FKContract_Traveller]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[Contract_Traveller]  WITH CHECK ADD  CONSTRAINT [Contract_Traveller_Traveller_Contract_Traveller_FKContract_Traveller] FOREIGN KEY([FKContract_Traveller])
REFERENCES [dbo].[Traveller] ([ID])
GO
ALTER TABLE[dbo].[Contract_Traveller] CHECK CONSTRAINT [Contract_Traveller_Traveller_Contract_Traveller_FKContract_Traveller]
GO
/****** Object:  ForeignKey [CruiseCompany_CruiseCompany_SeasWithOfferedCruises_CruiseCompany_FKSeasWithOfferedCruises]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[CruiseCompany]  WITH CHECK ADD  CONSTRAINT [CruiseCompany_CruiseCompany_SeasWithOfferedCruises_CruiseCompany_FKSeasWithOfferedCruises] FOREIGN KEY([FKSeasWithOfferedCruises])
REFERENCES [dbo].[CruiseCompany_SeasWithOfferedCruises] ([ID])
GO
ALTER TABLE[dbo].[CruiseCompany] CHECK CONSTRAINT [CruiseCompany_CruiseCompany_SeasWithOfferedCruises_CruiseCompany_FKSeasWithOfferedCruises]
GO
/****** Object:  ForeignKey [CharterCompany_CharterType_CharterCompany_FKTypeOfCharter]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[CharterCompany]  WITH CHECK ADD  CONSTRAINT [CharterCompany_CharterType_CharterCompany_FKTypeOfCharter] FOREIGN KEY([FKTypeOfCharter])
REFERENCES [dbo].[CharterType] ([ID])
GO
ALTER TABLE[dbo].[CharterCompany] CHECK CONSTRAINT [CharterCompany_CharterType_CharterCompany_FKTypeOfCharter]
GO
/****** Object:  ForeignKey [Travel_Company_Travel_FKCompany]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[Travel]  WITH CHECK ADD  CONSTRAINT [Travel_Company_Travel_FKCompany] FOREIGN KEY([FKCompany])
REFERENCES [dbo].[Company] ([ID])
GO
ALTER TABLE[dbo].[Travel] CHECK CONSTRAINT [Travel_Company_Travel_FKCompany]
GO
/****** Object:  ForeignKey [ContractItem_Travel_ContractItem_FKPurchasedTravel]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[ContractItem]  WITH CHECK ADD  CONSTRAINT [ContractItem_Travel_ContractItem_FKPurchasedTravel] FOREIGN KEY([FKPurchasedTravel])
REFERENCES [dbo].[Travel] ([ID])
GO
ALTER TABLE[dbo].[ContractItem] CHECK CONSTRAINT [ContractItem_Travel_ContractItem_FKPurchasedTravel]
GO
/****** Object:  ForeignKey [Contract_ContractItem_Contract_FKItems]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[Contract]  WITH CHECK ADD  CONSTRAINT [Contract_ContractItem_Contract_FKItems] FOREIGN KEY([FKItems])
REFERENCES [dbo].[ContractItem] ([ID])
GO
ALTER TABLE[dbo].[Contract] CHECK CONSTRAINT [Contract_ContractItem_Contract_FKItems]
GO
/****** Object:  ForeignKey [Traveller_Traveller_Traveller_FKAssociatedTravellers]    Script Date: 2012-04-05 ******/
ALTER TABLE [dbo].[Traveller]  WITH CHECK ADD  CONSTRAINT [Traveller_Traveller_Traveller_FKAssociatedTravellers] FOREIGN KEY([FKAssociatedTravellers])
REFERENCES [dbo].[Traveller] ([ID])
GO
ALTER TABLE[dbo].[Traveller] CHECK CONSTRAINT [Traveller_Traveller_Traveller_FKAssociatedTravellers]
GO

/****** Did not script following | Script Date: 2012-04-05 

******/



It is a lot of SQL that you dont have to write yourself!

And if you look at the table diagram it will look like this after executing:



Almost correct! But as object relational mapping is a guess work you should modify this to suit your needs (and also there's still some bugs in the generator logic). See it as a way to generate a skeleton of your tables rather than the truth of how you should serialize your objects. Hope you try it out, have fun and maybe even fix the bugs at CodePlex for me! :)

PS. I made it on a big object model just to show that the codes handles it pretty well, start out with a single class first.

See you!