Homepage | About Me | Testing ASP.net Book | Best Blog Posts | Personal Projects | Follow me on Twitter | GitHub | SlideShare | RSS
Blog.BenHall.me.uk

Upgrading a project from Visual Studio 2005 to Visual Studio 2008

Thursday, August 30, 2007

While Visual Studio 2008 supports multi-targeting, sadly you are still required to convert the solution into the 2008 version.  I will briefly discuss how to convert a existing project from 2005 to 2008.

Visual Studio 2005 ASP.net 2.0 Website

To start with, I will discuss how to convert an ASP.net website. I've got an existing C# website stored on my file system which just containing a single Default.aspx page saying "This is a Visual Studio 2005 website." (I didn't get very far with it).

If we load Visual Studio 2008 (Beta 2) and select File > Open > Website and select the 2005 Project.  When we click open a dialog will be displayed

.NET Framework 2.0 Web Site Found

Clicking yes will load the website and add System.Core and System.Xml.Linq (not System.Data.Linq, you will need to add this manually yourself) and targeted for the .Net Framework 3.5.

Visual Studio 2005 Solution

For all other solutions, including ASP.net 2.0 solutions, when you load the project solution (File > Open > Solution) you will be represented with the conversion wizard, the same one as used when converting 2003 to 2005.

Visual Studio Conversion Wizard 

Visual Studio Conversion Wizard (2)

Visual Studio Conversion Wizard (3)

Visual Studio Conversion Wizard (4)

 Upon clicking close, your project will be loaded. However, it will still act and behave as a 2.0 application and still compile under the 2.0 framework.

2005WinFormApplication - Microsoft Visual Studio

Inside the actual solution file, the version text changes from

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005

to

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008

Because of this, when you try and load the project again in Visual Studio 2005 you will be given the following error message.

Microsoft Visual Studio

In order to add Linq functionality to the application you need to convert it to a .Net 3.5 application.  First, you need to change the Target Framework to .Net Framework 3.5 and then add references to the System.core.dll assembly.  In order to use Linq to SQL you will need to add System.Data.Linq.dll and for Linq to XML you will need to use System.Xml.Linq.dll.

Technorati Tags:

Labels:

Visual Studio Second Life User Group

So this is a little strange, but kinda makes sense.  There is a Second Life user group and today Brad Abrams is doing a talk on Silverlight.

I've never used Second Life before, so I might pop-in to have a look.  Second life is free (I always thought you had to pay...) and the client download is only 33mb (only...wouldn't have said that a few years ago).

Not sure if the evening is going to be hosted by the guys at http://www.sldnug.net, but it sounds separate.

Event Details:

Guest Speaker: Brad Abrams, Group Program Manager, .NET Framework

When: Thursday, August 30th, 3 – 4 PM PST - That's 10pm UK Time (I think).

Where: Visual Studio Island Auditorium in Second Life

Link: http://slurl.com/secondlife/Microsoft/101/123/30/

Technorati Tags: ,

Labels: ,

What are the files the Linq to SQL designer creates?

Wednesday, August 29, 2007

When I spoke about SQLMetal the files it generates are pretty straight forward.  You ask for code, it generates code.  You ask for the mapping file, it generates you the xml mapping file, and asking for the dbml generates you a very similar xml file.  So what files does the Linq to SQL designer built into Visual Studio generate?

The main file which you interact with is the dbml file.  When you open this file, it launches into the designer. However, the file actually holds xml.  If you right click on the file and choose open with, you can view the file as XML.  You will then see that the file actually containing information about the entries included in the datacontext.  This file contains all the meta data for the tables, such as column type, name and other information.

One of the other files is the .dbml.layout file which contains XML.  This file simply tells the designer how to layout the entries on the surface.  Not really any need to edit this by hand.

Finally, the most important file is .designer.cs.  This contains all of the C# implementation for the DataContext and is generated based on the information in the designer/dbml file.  As the built in designer only creates attribute based files, all of the database information is also in this time. 

Finally, when the project is compiled, the only file taken into consideration and included within the assembly is the .designer.cs which contains the DataContext code.

Technorati Tags: ,

Labels: ,

LINQ In Action Book - Early Review

linqinaction While Linq isn't officially due out until Feburary, there are already a number of books available.  The book I have been reading is the Linq In Action book which I have had access to via the Manning Early Access Program as a PDF ebook.  This is a good way to access the book as you can download the nearly finished chapters at certain points while the book is being completed which allows you to read it in blocks and gain a good idea of the technology.  When the book is finally finished, you will be sent either a printed copy or the final ebook version.

On Monday, all of the chapters where made available to download via the program.  I still have to read the final few chapters, however I just wanted to comment on how good I have found this book.   The book doesn't just focus on Linq to SQL, but instead covers all aspects of the framework so you will have a great understanding.

The book starts with an introduction of what Linq is and builds this more and more throughout the book.  It provides a very good high level overview of all the sections, however goes deep into the inner works of Linq to give you an in-depth understanding when and where it is required.  It also covers the advance parts of Linq, such as extending Linq and Linq in the different layers of the application so you will be really ready to use the technology on your first project.

No matter what level of understanding you have of linq, be it your trying it for the first time or already have a good understand this is a really good book to read and you will gain a lot from reading it.  Once I get the final version of the book, I will give it another read. 

Table of Contents

Part I - Getting started
 1. Introducing LINQ
 2. C# and VB.NET language enhancements 
 3. LINQ building blocks
Part II - Querying objects in memory
 4. Getting familiar with LINQ to Objects 
 5. Working with LINQ and DataSets 
 6. Beyond basic in-memory queries
Part III - Mapping objects to relational databases
 7. Getting started with LINQ to SQL
 8. Peeking under the covers
 9. Advanced LINQ to SQL features
Part IV - Manipulating XML
 10. Introducing LINQ to XML 
 11. Querying and transforming XML 
 12. Common LINQ to XML scenarios
Part V - LINQing it all together
 13. Extending LINQ
 14. LINQ in every layer

The book should be in stores in January 2008, but you can purchase and download the ebook today. You can download the first chapter for free.

http://www.manning.com/marguerie/

The book website is http://linqinaction.net/

Technorati Tags: ,

Labels:

ADO.NET Entity Framework Beta 2 & August Tools CTP

Monday, August 27, 2007

Mike Taulty has been busy and just posted loads of information on the ADO.Net Entity Framework (One of the joys of working for Microsoft - early access!). Really recommend you head over to his blog and check it out.

To get started, the following links are useful. 

Readme

http://download.microsoft.com/download/d/0/8/d0838c32-33cc-41fc-b839-50a2db658397/Readme.htm

Runtime

http://www.microsoft.com/downloads/details.aspx?FamilyID=F1ADC5D1-A42E-40A6-A68C-A42EE11186F7&displaylang=en

Tools

http://www.microsoft.com/downloads/details.aspx?FamilyID=09A36081-5ED1-4648-B995-6239D0B77CB5&displaylang=en

Getting Started Video

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/08/27/9604.aspx

I haven't had chance to look into this yet so expect more posts over the next few days and weeks.

Technorati Tags:

Labels:

SQLBits Registration Open

Today the SQLBits registration opened to the general public.  Taken from the website:

"You will need to register on the site and then select the 10 sessions (http://www.sqlbits.com/information/PublicSessions.aspx)  you would most like to see. We will use this voting to help decide which sessions are to be run. We have 36 sessions and only 20 slots. Even I can do those maths.

Once you have selected and saved your selection you will be given the registration URL.

Please don't just click any 10 because then you won't get the sessions you want to see.

We only have 300 places so make sure you register quickly."

Technorati Tags:

Labels:

LINQ to SQL Beta2 to RTM Key Changes

Dinesh just posted a list on the forum of the key changes which will occur between Beta 2 and RTM for Linq to SQL.

Read them here:

http://forums.microsoft.com/MSDN/showpost.aspx?postid=2061468&siteid=1&&notification_id=27123913&message_id=27123913

Main changes are renaming of the Add/Remove methods to make them more descriptive.  They will now be called InsertOnSubmit() and DeleteOnSubmit(). 

The OnValidate() method will now have a ChangeAction value so you know if your validating a delete, insert or update.  This will be very useful.

One thing mentioned which was interesting is that the next release will be RTM and they are skipping RC.  Tiscali (ADSL provider at the moment) will be happy...

Technorati Tags: ,

Labels:

DeskSpace (Previously Yod'm 3D)

Recently when I did my first NxtGenUG nugget, I used an application called Yod'm 3D to flip between powerpoint and demo and it worked well.  The application allows you to have multiple virtual desktops.  I also notice Mike Ormond (Microsoft DPE) used it for his WPF presentation.   It impressed Dave anyway.

Shortly after I found the software, Otaku Software purchased the source code/rights.  The company already do a software designed at making life easier so its a good fit into their portfolio.  This morning, I received an email saying they have released a beta of their version, called DeskSpace.

Improvements

1) Still drag and drop install, however you can now set it to start on windows startup.

2) Performance improvements.

3) Improved icons/backgrounds.  When you press the key combo (shift, ctrl, alt) an icon appears on your cursor. 

4) Includes mouse dragging support, hold the combo keys and use the mouse to drag to the different desktops.

5) Improved Vista support. Last time I used Yod'm, it wasn't happy. 

6) Appears to work well with Powerpoint running.

7) Improved context menu, now displays icons of the application on each desktop and you can go to that application directly.

Some good progress has been made.  Its very useful if your giving powerpoint/demo presentation but also allows you to have a 'work' desktop and a 'play' desktop which you can switch between with a simple keystroke. 

There are a few things which I don't like, but this is it's first release and it doesn't stop the actual functionality.

1) It keeps setting my MSN status to busy.

2) Using WinKey + Desktop# (1,2,3,4) doesn't seem to work.

3) When you flip over to a desktop for the first time, the screen is blank as it hasn't been loaded yet.  Second time it works fine.

4) If you kill the app via Task Manager and reload it, it doesn't remember what desktops it had open.

Apart from that, it looks to work great!  Now they have the core base completed, hopefully they will start adding some nifty features.

It's currently in beta/30 day trail, you can signup to join the program at their website:

http://www.otakusoftware.com/deskspace/

Definitely worth a look.  It's due to retail around $19.95 USD, with some discounts for education etc.  I've heard, beta testers get 50% off, if so I will definitely grab a copy.  Always handy to have on your tools list. 

Technorati Tags: ,

Labels: ,

Remove Recent Projects from Visual Studio 2008

Thursday, August 23, 2007

Ever wanted to remove an item from the recent projects menu on the start page of Visual Studio?

The list is stored in the registry under:

HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\ProjectMRUList

Here, you will find a list like this:

File1 Reg_Expand_Sx Path

File2 Reg_Expand_Sx Path

File3 Reg_Expand_Sx Path

File4 Reg_Expand_Sx Path

You just need to delete the items you don't want.  Note: If you delete item 2 you will need to rename item 3 and 4 so there are no gaps in the naming. (3 becomes 2, 4 becomes 3).

Another way is just to wait until you have opened more projects.  Also, if you delete the project solution and try and open it, Visual Studio will display a dialog asking if you want to remove it from the list.

Technorati Tags:

Labels:

Linq to SQL - Mapping Tables to Objects

In this post I am going to cover how Linq to Sql deals with the mappings between the objects in your assembly and the database.

There are two ways in which Linq to SQL handles the mapping, either AttributeMappingSource or XmlMappingSource.  By default, Linq uses AttributeMappingSource where all the information which links tables and columns to classes and properties are stored as attributes within the DataContext.

For example, this code links the Categories object to dbo.Categories table.

[Table(Name="dbo.Categories")]
public partial class Categories : INotifyPropertyChanging, INotifyPropertyChanged

While this code links the CategoryID property to the column, also called CategoryID.

[Column(Storage="_CategoryID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int CategoryID

There are a few advantages to having attribute saved within the code. Reading the code is easier as everything is in a single place and the compiler can verify that everything is correct.

The other choice is to use an external file which contains all the database information as XML.  This is then combined with a DataContext (which doesn't have attributes) in order to be able to query the database.

The external mapping file can be generated by SQLMetal as I discussed in my previous post.  The following command would generate the file.

SqlMetal /server:. /database:northwind /map:"%~dp0Northwind.map"

The contents of the map file would look something like this.

<Table Name="dbo.Categories" Member="Categories">
  <Type Name="Categories">
    <Column Name="CategoryID" Member="CategoryID" Storage="_CategoryID" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
    <Column Name="CategoryName" Member="CategoryName" Storage="_CategoryName" DbType="NVarChar(15) NOT NULL" CanBeNull="false" />
    <Column Name="Description" Member="Description" Storage="_Description" DbType="NText" UpdateCheck="Never" />
    <Column Name="Picture" Member="Picture" Storage="_Picture" DbType="Image" UpdateCheck="Never" />
    <Association Name="FK_Products_Categories" Member="Products" Storage="_Products" ThisKey="CategoryID" OtherKey="CategoryID" DeleteRule="NO ACTION" />
  </Type>
</Table>

We can then generate the DataContext code and tell it to use the external file by having both map and code as options, like below.

SqlMetal /server:. /database:northwind /map:"%~dp0Northwind.map" /code:"%~dp0Northwind.cs"

The datacontext would then just be the code.

public partial class Categories : INotifyPropertyChanging, INotifyPropertyChanged

and

public int CategoryID

Like with attributes, there are also advantages to be had when using an external file.  For one, you can make schema changes without having to recompile the application - but you could only make minor changes without breaking the relationship.  Another advantage is that the same mapping file could be used by multiple DataContext objects.   One possible disadvantage could be the two becoming out of sync, which would result in runtime errors.

However, to use this in our application we need to specify that we want to use the external mapping source, we could just modify the DataContext constructors to do this for us.

Northwind db = new Northwind(LinqConsole.Properties.Settings.Default.NorthwindConnectionString, XmlMappingSource.FromXml("Northwind.map"));

So which one to use?  Well it really depends on your requirements, for the most part using either one will be fine.

Finally, the instead of SQLMetal connecting to the database directly to generate the mapping and datacontext, it can gain all the information from the dbml file.  The dbml file contains all the database metadata and everything SQLMetal requires to generate the code and mappings.

To generate the dbml you use the command.

SqlMetal /server:. /Database:Northwind /dbml:Northwind.dbml

Which creates an XML file containing data like this.  It looks similar to the mapping file, however is slightly different.

<Table Name="dbo.Categories" Member="Categories">
  <Type Name="Categories">
    <Column Name="CategoryID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
    <Column Name="CategoryName" Type="System.String" DbType="NVarChar(15) NOT NULL" CanBeNull="false" />
    <Column Name="Description" Type="System.String" DbType="NText" CanBeNull="true" UpdateCheck="Never" />
    <Column Name="Picture" Type="System.Data.Linq.Binary" DbType="Image" CanBeNull="true" UpdateCheck="Never" />
    <Association Name="FK_Products_Categories" Member="Products" OtherKey="CategoryID" Type="Products" DeleteRule="NO ACTION" />
  </Type>
</Table>

Then to use the dbml to generate the mapping file and code instead of a database connection you would use this command.

SqlMetal /map:"%~dp0Northwind.map" /code:"%~dp0Northwind.cs" Northwind.dbml

Technorati Tags: ,

Labels: ,

assembly:InternalsVisibleToAttribute - Test Internal Methods

One of the problems with unit testing is that you can only test public accessible items within the assembly.  To solve this you have to make more items visible and increase your public interface in order to be able to unit test the item.  This is bad if you are planning on making your API useable outside of your own system as changing the public interface could cause breaking changes in other peoples' systems.  It also means your internal system is exposed and useable to anyone.

The InternalsVisibleTo attribute solves this problem.  By including this within your AssemblyInfo.cs you can set which assemblies can access you internal items.  This means you can test your assembly without having to set everything to public.  You even get intellisense support with all of your internal methods listed.

If we have an assembly MyAPI which is tested by MyAPI.Tests.  If in our MyAPI.class we have the following code

public class MyPublicClass
{
    public bool IsValid()
    {
        return true;
    }

    private bool AllowedAction(string action)
    {
        if (string.IsNullOrEmpty(action))
            return false;

        return true;
    }
}

Which has the following test

[TestFixture]
public class MyPublicClassTests
{
    [Test]
    public void TestIsValid()
    {
        MyPublicClass cls = new MyPublicClass();
        Assert.IsTrue(cls.IsValid());
    }
}

In order for us to test the AllowedAction method we would have to make it public.  But then everyone using the API would be able to use it and we would be unable to refractor this method for the lifetime of the API.  By adding the attribute to the MyAPI.AssemblyInfo file and change the method from private to internal.

[assembly: InternalsVisibleTo("MyAPI.Tests")]

internal bool AllowedAction(string action)
{
    if (string.IsNullOrEmpty(action))
        return false;

    return true;
}

[Test]
public void TestActionAllowed()
{
    MyPublicClass cls = new MyPublicClass();
    Assert.IsTrue(cls.AllowedAction("Test"));
}

This is great, we have only increased our public interface to our test method yet all the other assemblies cannot access it.  However, one problem with this is that if another malicious user came along with an assembly called MyAPI.Tests then they also would be able to access the internal actions.

Then is why it is recommend to sign the test assembly and include the public key within the attribute. In order to obtain the public key, you need to run the sn application on the assembly.

sn -Tp MyAPI.Tests.dll

The attribute would then look like this.

[assembly: InternalsVisibleTo("MyAPI.Tests,PublicKey=00240000048............de35d15ffae")]

However, it means MyAPI must have a strong name/be signed.

An example of this being used is with the System.Data.Linq assembly, you can see that Microsoft use this attribute to allow the assembly to be tested by another assembly called DLinq.Unittests.

[assembly:InternalsVisibleTo("DLinq.Unittests,PublicKey=########")]

MSDN Link - http://msdn2.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

Technorati Tags: , ,

Labels: , ,

SQLBits - Sessions and speakers are now available

Tuesday, August 21, 2007

The sessions for the SQLBits (SQLBits.com - UK SQL Server Community) conference has been published to the site

Registration isn't open yet, (Simon says a few more days), but if you pre-register on the site you will be emailed the link as soon as its live.

Sounds like it will be a great event.

Technorati Tags: ,

Labels: ,

The power of SQLMetal

Monday, August 20, 2007

During my time with Linq, I have created all of my DataContext's using the designer in Visual Studio 2008.  I've been aware of SQLMetal but always thought it was just a command line tool which didn't offer much - after looking at it today, I am wrong.  SqlMetal is very powerful and cool! 

To start with, SqlMetal can generate a DataContext for your entire database with a single command.  This is very useful if you have a large number of tables in your system, as dragging and dropping them onto the designer would have got boring very quickly. By entering this command we can have our Northwind datacontext created for us and saved to the file NorthwindDataContext.cs.

SqlMetal /server:. /database:Northwind /code:NorthwindDataContext.cs

We can then include the class within our project and use it as if the designer had created it.  However, it would have been nice if it accepted an array of tables to exclude, or only include, during the creation process.  Also it also doesn't create an overload for the constructor so it uses the App.config connection string like the designer does.

We can also get SqlMetal to include all of our views, functions and sprocs

SqlMetal /server:. /database:Northwind /code:NorthwindDataContext.cs /views /functions /sprocs

If it cannot extract an item from the database into code, then it will continue with the process and report the error at the end.  In my case I had this single error:

warning SQM1014: Unable to extract stored procedure 'dbo.sp_upgraddiagrams' from SqlServer. Invalid object name 'dbo.dtproperties'.

I think that's a really powerful feature and makes life a lot simpler than manually creating everything. 

In the above example, we are asking SQLMetal to generate our DataContext as code. However, SQLMetal can also output the dbml (/dbml:file.dbml) or mapping (/map:file.xml) file for the database.

By default, the Linq to SQL designer will pluralise all of the table names (Orders => Order).  SQLMetal doesn't do this by default, however by adding /pluralize you can force the changes.  I've spoken about this before.

You can define the language which the code should be generated using the /language:<language> option and you can set the namespace for which the DataContext should be part of by using the /namespace:<name> property.

If you wanted a different name for your datacontext class then you could use the /context:<type> option, by default it uses the same name as the database.

Onto my favourite two options. The entitybase option (/entitybase:<type>) allows you to specify a class or interface which all the entities in the datacontext must inherit from.

SqlMetal /server:. /database:northwind /code:"%~dp0Northwind.cs" /entitybase:MyNamespace.ITable

The code generated would then look like this:

[Table(Name="dbo.Categories")]
public partial class Categories : MyNamespace.ITable, INotifyPropertyChanging, INotifyPropertyChanged

This is a very useful feature, as discussed in the previous post we should place all custom code in a partial class. I don't think interfaces are best used in this situation as you would need to implement it on all the entities, however it could be useful for base classes.

Finally, /serialization:Unidirectional option adds a [DataContract()] attribute to the classes and [DataMember(Order=#)] to the properties.  These two attributes allow for objects to be serialised which means they can be used with WCF.

Ben's top tip

Use a classic batch file (.bat) to store your SQLMetal command. Then when you need to regenerate the DataContext you will not end up using different settings by mistake.  This batch file can then be included within your source control for the rest of the team to use.  Use the "%~dp0" variable to ensure it runs from its current location and not the default command line location, generally it should be your project folder.

Given this command in a batch file, it will convert the %~dp0 to the path where the path file is located.

SqlMetal /server:. /database:northwind /code:"%~dp0Northwind.cs"

Becomes

SqlMetal /server:. /database:northwind /code:"E:\PATH\TO\MY\PROJECTS\Northwind.cs"

Technorati Tags: , ,

Labels: ,

Effects database changes have on Linq to SQL

Sunday, August 19, 2007

In this post I'm going to discuss the effects of changing the underlying database table has on Linq to SQL and to make people aware of the potential issues as quite a few people seem to be asking about this.  Changes to the underlying database structure is a problem with any application and data access, be it ADO.net and Datasets, SubSonic, Linq or any other approach.  If the data structure is changed without your application being updated or knowing about the change then you will run into problems.

In this application, I will be working with the following entity.

Table

Writing queries against this isn't a problem.   For example, if we wanted to write everything out to the console we could do this:

var query = from p in db.Persons
                   select p;

foreach (var person in query)
{

    Console.WriteLine("{0} | {1} | {2} | {3}",
                                 person.id, person.Name, person.PostCode, person.Phone);
}

This could result in:

1 | Bob | AAA | 123
2 | Jack | BBB | 0
3 | Gill | MB | 12346

Adding additional columns

If we added an additional column, say email,  onto our table then the above could would still work fine however we would never be able to access that additional column until we regenerated our DataContext (see below).

If we inserted a new person then this also wouldn't stop our application from working, unless the new column was set to be NOT NULL, however we wouldn't be able to fill in that information.

Person newP = new Person();
newP.Name = "Test";
newP.PostCode = "TTTT";
newP.Phone = new Random().Next();
db.Persons.Add(newP);
db.SubmitChanges();

Changing column data types

Changing the types in our database could cause our application to stop functioning. If we change the int to a bigint in the table design then our query would not longer run because Linq couldn't convert a long to an int.  If we did something like change a nvarchar(50) to a nvarchar(MAX) then this wouldn't cause a problem as Linq treats them both as a string.

Removing columns

Removing columns is when most problems will occur. If I removed the phone column from the table and execute the query then I would receive a SqlException - Invalid column name 'Phone'.  If our query was like below, then it wouldn't cause an exception as Phone would never be called.

var query = from p in db.Persons
                        select new { p.id, p.Name, p.PostCode };

However, when inserting data we will always get a SqlException even if the column was not populated as Linq will try and insert null into the column.

Regenerating our DataContext

So, if you are changing the underlying table, updating the DataContext in your system is also required.  In Visual Studio 2008 there are only two ways to update a DataContext.  Either, regenerate the entire datacontext using SQLMetal, or remove the table from the datacontext using the designer and then insert it again.  Shame there isn't a button called refresh on the designer.

Thankfully, all the objects are partial, so you can store all your custom logic in a separate class which will not be affected by this.  However, if you go against this and write your logic in the actual DataContext.designer.cs class then when you recreate it, you will lose these changes.

Technorati Tags: ,

Labels: ,

NxtGenUG Cambridge

Friday, August 17, 2007

NxtGenUG have just announced that they have expanded into another region - Cambridge with the meetings being held at Microsoft Research! 

"The 'Launch' meeting will be held at Microsoft Research on Tuesday 18th September 2007 and will feature Mike Ormond from Microsoft DPE speaking on Silverlight Microsoft's new Rich Web Application Development Platform. We'll also have a speaker from Microsoft Research covering a fanscinating new subject such as F#, watch out for details! Finally Rich, Dave and John will be there to do something or other, probably involving 'swag' (tut). Anybody is welcome to attend the meeting whether they are a NxtGenUG member or not. Just go to the NxtGenUG site at http://www.nxtgenug.net, register for FREE and book your place! The evening starts at 6:30pm and ends at 9pm."

NxtGenUG meetings are always fun, so if your in the area come along and see what you think.

Details of how to get to MSR can be found at http://research.microsoft.com/aboutmsr/visitmsr/cambridge/default.aspx

Technorati Tags:

Labels:

Converting IEnumerable<T?> to IEnumerable<T>

Wednesday, August 15, 2007

This morning on the forum there was a question regarding nullable types (ie decimal?) and how to convert an IEnumerable collection containing nullable types to one containing the equivalent non-nullable type (decimal).  This raised an interesting question, how do you convert a collection containing one type of object, into a collection containing another type of object, be it nullable>nonnullable or otherwise.

To start with, I looked at the extension methods of IEnumerable<T>, and in particularly Cast<>.  However, if the value is null then we are going to have to handle it differently which cast doesn't have the ability to do.  So no luck there and there didn't seem any other methods.

I then looked at the methods which List<> contains, this implements IEnumerable<> so its part of the same type.  List<> does have a method which allows for this requirement, called ConvertAll() which takes a Converter object, which in turn takes a method name which is called for each object in the list to handle the conversion.  This then allowed me to write this code:

List<decimal> nonNull;
List<decimal?> nullable = new List<decimal?>();

nullable.Add(null);
nullable.Add(1);

nonNull = nullable.ConvertAll(new Converter<decimal?, decimal>(ConvertToNonNull));

foreach (var i in nonNull)
{
   Console.WriteLine(i);   
}

public static decimal ConvertToNonNull(decimal? nullValue)
{
    return nullValue.GetValueOrDefault(0);
}

ConvertToNonNull is called for every item in the list, taking advantage of generics to keep everything strongly typed.  The GetValueOrDefault() is available to use on all nullable types, you simple give it the value as a parameter you want it to return if the value is null.

The problem is that you have to be working in terms of List<> and not IEnumerable<>.  The solution, create your own extension method for IEnumerable<>.

public static class IEnumerableExtension
{
     public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Converter<T, TOutput> converter)
     {
         if (converter == null)
             throw new ArgumentNullException("converter");

         List<TOutput> list = new List<TOutput>();

         foreach (T i in collection)
         {
             list.Add(converter(i));
         }

         return list;
     }
}

The extension method above attaches itself to IEnumerable<> and takes a Converter as a parameter - just the same as List does.  I then check to make sure its not null,  create a new internal list of the outputting type (need a way to hold the converted items internally).  Then for each item in the source collection, I call the converter method.  Finally I return the list as a return type of IEnumerable<>.  Here's the calling code.

IEnumerable<decimal> notNull;
IEnumerable<decimal?> INull;

INull = nullable; //Original list.

notNull = INull.ConvertAll(new Converter<decimal?, decimal>(ConvertToNonNull)); //My new extension method

foreach (decimal i in notNull)
{
    Console.WriteLine(i);
}

One of the nice things about extension methods is that if a method, with the same name and parameter list, is defined locally within the class then it overrides the extension implementation.  So, the List<>.ConvertAll() functionality is not affected.

Hope you find a use for this.

Technorati Tags: ,

Labels: ,

MbUnit - New website and Documentation

Monday, August 13, 2007

Today, we finally launched the new Mbunit Website and we have the documentation in a great format online and offline.  Dan Maharry and I have been working on this for a while, I have been putting together the site and the Sancastle/DocProject setup while Dan has been working hard on the actual content - so it will actually all make sense!

Dan has blogged about the docs more over @ http://blogs.ipona.com/dan/archive/2007/08/13/8417.aspx

Visit the new main site at - http://www.mbunit.com

Visit the new documentation site at - http://docs.mbunit.com

Download the documentation in an offline format - http://docs.mbunit.com/Mbunit.Documentation.chm

We are really interested in hearing your feedback on this, so please let us know.

Technorati tags:

NxtGenUG - Mind your TABLE manners!

Tonight I attended a NxtGenUG meeting with Dave Sussman giving his talk on CSS 101, focusing on using CSS instead of tables for your layout.  Personally, I trend to use tables for layout and CSS for everything else, however Dave's talk definitely opened my eyes on how CSS, I wasn't even aware that it improved your bandwidth usage.  Seeing the CSS adapters was good as I haven't looked at these before and some of his points on CSS and Forms was interesting as this is my major bug-bear with CSS.

I still have some issues with CSS where it seems to produce some unexplainable actions (unexplainable to me anyway, but i'm really not a CSS guru). 

The talk was really interesting and Dave is a good speaker so was an enjoyable session.

Rich gave a nugget on the Hawkeye tool which is a cool app for your toolkit.  Really pleased Rich showed it's real power of enabling buttons which shouldn't be enabled.

image I also gave "The Sandcastle Nugget" about Sandcastle, DocProject and GhostDoc.  I think it kinda went alright. Nothing went wrong, but there where one or two things which I wanted to mention but forgot - any maybe went a bit quick. I really need to record myself and play it back and maybe some 'expert' coaching.

Download the slides here

A good night all round, there was also new chairs/sofas which were really comfortable!  Cheers guys.

Related Sandcastle posts

Sandcastle, DocProject and creating custom topics

SandCastle and DocProject

SandCastle - Creating a website

SandCastle - What you need to know

Technorati tags: ,

Labels: ,

Linq to SQL - DataLoadOptions - Does it improve performance?

Sunday, August 12, 2007

Following on from my previous post on DataLoadOptions, I decided to do a quick test to see if it does actually improve performance, even with its limitations.

If we take this query, with DataLoadOptions only a single query is executed, while with it not set a query is executed per order.

DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Customer>(Customer => Customer.Orders);
db.LoadOptions = options;

var query = from c in db.Customers
                        select c;

            foreach (var c in query)
            {
                Console.WriteLine("{0}, Phone: {1} with {2} orders", c.ContactName, c.Phone, c.Orders.Count);
            }

Without using DataLoadOptions, it took 1,739,904 Ticks to execute, while with using them it took 1,487,722 Ticks. An improvement, but nothing ultra special.

If we consider this query, which if you have read the previous, causes a query to be executed for each order even with DataLoadOptions on:

DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Customer>(Customer => Customer.Orders); options.LoadWith<Order>(Order => Order.Order_Details);
db.LoadOptions = options;

var query = from c in db.Customers
                     select c;

         foreach (var c in query)
         {
             Console.WriteLine("{0}, Phone: {1}", c.ContactName, c.Phone);
             foreach (var o in c.Orders)
             {
                 Console.WriteLine("Order Details for OrderID: {0} with {1} lines", o.OrderID, o.Order_Details.Count);

                 foreach (var od in o.Order_Details)
                 {
                     Console.WriteLine("Product ID: {0}", od.ProductID);
                 }
             }
         }

Without using DataLoadOptions, it took 10,003,725 Ticks to execute.  While using DataLoadOptions, taking into account the time to setup the options, it took 6,536,320 Ticks.  Much clearer performance improvements when a larger number of queries are being executed.

There is definitely performance improvements to be had even with it not being able to load all the data in at the same time and so should be used when executing these kinds of queries.

However, what happens if we are not using the Order/Order Details information and simply just using Customer data?  Executing our first query again but without c.Orders.Count, with options set it takes 1,609,867 Ticks, without it takes 1,174,217 Ticks.  So, if your not using them, then there is additional overhead to be aware of.

Technorati Tags: , ,

Labels: , ,

Linq to SQL - DataLoadOptions (Previously DataShape)

DataLoadOptions allows you to specify which child entities you automatically want to be loaded with their parent entity. By defining how the data should be loaded, we can reduce the number of requests made to the database to retrieve information and thus improving performance of our application.
Take this code for example:

var query = from c in db.Customers
                  select c;

foreach (var c in query)
{
   Console.WriteLine("{0}, Phone: {1} has {2} orders", c.ContactName, c.Phone, c.Orders.Count);
}

This is a simple query which outputs the name, telephone number and the number of orders they have to the console.  There doesn't look to be anything wrong with this, however if we run SQL Profiler that a large number of queries are being executed.

The query process is that all the customers are loaded into memory, and then for each customer a query is made to the orders table to return how many records they have which is then counted in memory.  Having queries like this will soon put pressure on your database.

This is where DataLoadOptions plays a part.  We can define that when a Customer object is loaded from the database, that all the Orders for that Customer should also be loaded with this code.

DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Customer>(Customer => Customer.Orders);
db.LoadOptions = options;
var query......

Now if we re-run the application, instead of having a query for each customer to find out the number of orders, we just have a single query being executed which returns the Customer and Order information.

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country],
[t0].[Phone], [t0].[Fax], [t1].[OrderID], [t1].[CustomerID] AS [CustomerID2], [t1].[EmployeeID], [t1].[OrderDate], [t1].[RequiredDate], [t1].[ShippedDate], [t1].[ShipVia],
[t1].[Freight], [t1].[ShipName], [t1].[ShipAddress], [t1].[ShipCity], [t1].[ShipRegion], [t1].[ShipPostalCode], [t1].[ShipCountry], (
    SELECT COUNT(*)
    FROM [dbo].[Orders] AS [t2]
    WHERE [t2].[CustomerID] = [t0].[CustomerID]
    ) AS [count]
FROM [dbo].[Customers] AS [t0]
LEFT OUTER JOIN [dbo].[Orders] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
ORDER BY [t0].[CustomerID], [t1].[OrderID]

Changing the foreach loop to output the order information will still only result in a single query being executed on the server.

foreach (var c in query)
{
    Console.WriteLine("{0}, Phone: {1}", c.ContactName, c.Phone);
    foreach (var o in c.Orders)
    {
        Console.WriteLine("OrderID: {0}", o.OrderID);
    }
}

However, it doesn't solve all of our problems.  If we wanted a query which provided details on the Order Lines within the ProductID being outputted, we could write something like this:  

foreach (var c in query)
{
    Console.WriteLine("{0}, Phone: {1}", c.ContactName, c.Phone);
    foreach (var o in c.Orders)
    {
        Console.WriteLine("Order Details for OrderID: {0} with {1} lines", o.OrderID, o.Order_Details.Count);

        foreach (var od in o.Order_Details)
        {
            Console.WriteLine("Product ID: {0}", od.ProductID);
        }
    }
}

You would have thought that by adding the following code we would be able to limit the number of queries:

options.LoadWith<Order>(Order => Order.Order_Details);

Sadly, this is not the case and will still cause a query to be executed for each customer, in fact it is actually for each order. According to Michael Pizzo on the product team, this is by design with this explanation:

In LINQ to SQL, in order to reduce the complexity and amount of data returned by the join query required to do span, only one association in any given query is actually spanned in. LINQ to SQL picks the deepest level association in the query to do the join in order to minimize the number of queries generated.  So, in this case, by adding a span between orders and order_details, you are basically "hiding" any span of orders.

DataLoadOptions can improve the performance of your application and something which you should remember when writing Linq to SQL queries.  However, if we are going more than one layer deep, you are still going to have a huge number of queries being executed.  Remember to run SQL Profiler to make sure your application isn't going to take out your production server(s).

Technorati Tags: , ,

Labels: , ,

Imagine Cup 2007 Software Design Winners are - Thailand

Friday, August 10, 2007

The winners of the Imagine Cup 2007 Software Design Challenge are a Team 3KC Returns from Thailand with their entry Project LiveBook!

The only bit of information I could find on the team is within Google cache, with the only thing interesting detail being the integration into Wikipedia and Encarta.

Channel 8, the new student portal from Microsoft, have done a series of videos from the Imagine cup, sadly Thailand or the UK are not online yet.

Well done to all the teams who have won, especially Ireland who made it into the last 6.

Press release @ http://www.microsoft.com/presspass/press/2007/aug07/08-10ImagineCupWinnersPR.mspx

UPDATE: Information on each of the teams can be found here : Imagine Cup- Software Design Finals

Technorati Tags:

Labels:

Windows Live Folders becomes Live SkyDrive

Thursday, August 09, 2007

Today, Windows Live Folders was renamed to Windows Live SkyDrive.   This service currently offers 500Mb of free online disk storage space.   When the service was first announced, it wasn't open in the UK however it seems to have expanded as I am now able to use the service.

My initial thoughts are, do I really want all of my documents online?  I thought it would be cool to have them online, but in reality, i'm not sure I do want it.  The site mentions that your personal data is password protected with your Live ID and the site uses SSL.  Well, SSL is only a limited form of protection and doesn't stop anything if there is a vulnerability in the site.  Also, I haven't heard anything about how the files are actually stored on the disk?  I know some services use Blowfish encryption for an added layer of protection while others use Advanced Encryption Standard (AES) which is the standard encryption algorithm of the US government.  So what encryption does SkyDrive use?  If I knew for a fact they where using encryption which protected the files at all points along the journey then I would be happier.  However, if my Live ID was hacked then this wouldn't be any good away....

Moving onto the service, everyone has their own reasons for wanting to store there files online, for me the main reason is an off-site backup solution.  I'm sure this service will be linked into Windows Home Server so files could be automatically sync'ed.

As for the user experience, there are three levels of sharing - Personal, Shared, Public. As mentioned, Personal are protected by your Windows LIve ID,  shared can be accessed by defined users using their live ID and you decide what they can and cannot do (read/write) and the public folders can be access by anyone and they can only read.

Uploading files is initially limited to 5 files at a time, which is a very slow process.  However, you can download a ActiveX addin which allows you to drag and drop any files onto the upload surface embedded in the webpage which greatly improves the experience.

The UI is easy to navigate.  At the moment, editing files is very limited. You have to download the file locally, make the change, then re-upload the file.  At the moment there is no way to integrate the service into Windows, for example using WebDav and as a Network Location.  I'm guessing security together with usability are the key here.

I'm sure I will use the service in the end as it will solve a number of problems and will be really interesting when the API is released. For the moment, I think I will see how others get on.

Technorati Tags: , ,

Extending DataContext using Extension methods

Extension methods are great as they allow you to extend any class within C# 3.0 with the instance of the class being passed in as a parameter. 

In C# 2.0 we had an initial way with partial classes which allows us to extend classes with our own custom logic, however it only worked if the other class was marked as partial.

I talked before how we can extend the DataContext created by the designer (NorthwindDataContext) by using partial classes,  however if we wanted a method on all of the DataContext object in our system, we would have to create a partial class for each of them separate. This would result in a lot of duplicate code and a maintenance nightmare.

partial class DataClasses1DataContext { //... }

partial class DataClasses2DataContext { //... }

The other solution would be to add a partial class to the DataContext and have it be inherited by the other objects in the system, however this doesn't work as the DataContext class is not partial.

The answer is, Extension methods. Extension methods allow us to extend any object in the system, even if it is marked as sealed.  They require the following:

  • Be in their own public static class
  • Method be public static
  • use the 'this' keyword with the object we want to extend as the first parameter.  Other parameters can be added after this.
  • Accessible from the calling object.  If they are in there own namespace, the namespace needs to be referenced via a using directive.

Using this, we can extend the DataContext class and have all of our own DataContext's in the system implement our new functionality.

The following code could be used and access any information from the DataContext as a parameter:

namespace MyExtension
{
    public static class Extension
    {
        public static void PrintConnection(this DataContext dc)
        {
            Console.WriteLine(dc.Connection.ConnectionString);
        }
    }
}

This could then be accessed by any child object in the system like this:

DataClasses1DataContext db = new DataClasses1DataContext();
db.PrintConnection();

We are limited to the public interface of DataContext, but this is still a very useful technique. This also applies to any other object within .Net.

Technorati Tags: , ,

Labels: , ,

Linq to SQL - Difference between Concat and Union?

Wednesday, August 08, 2007

This morning I came across the Concat and Union methods within Linq to SQL.  From the surface they look very similar.

var query = from o in db.Orders
                        where o.ShipCountry == "UK"
                        select o;

var query2 = from o in db.Orders
                        where o.ShipCountry == "France"                       
                        select o;

var union = query.Union(query2);
Console.WriteLine(union.Count());

var concat = query.Concat(query2);
Console.WriteLine(concat.Count());

The SQL they is also very similar, Union is first, concat is second.

SELECT COUNT(*) AS [value]
FROM (
    SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
    FROM [dbo].[Orders] AS [t0]
    WHERE [t0].[ShipCountry] = @p0
    UNION
    SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate], [t1].[RequiredDate], [t1].[ShippedDate], [t1].[ShipVia], [t1].[Freight], [t1].[ShipName], [t1].[ShipAddress], [t1].[ShipCity], [t1].[ShipRegion], [t1].[ShipPostalCode], [t1].[ShipCountry]
    FROM [dbo].[Orders] AS [t1]
    WHERE [t1].[ShipCountry] = @p1
    ) AS [t2]

SELECT COUNT(*) AS [value]
FROM (
    SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
    FROM [dbo].[Orders] AS [t0]
    WHERE [t0].[ShipCountry] = @p0
    UNION ALL
    SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate], [t1].[RequiredDate], [t1].[ShippedDate], [t1].[ShipVia], [t1].[Freight], [t1].[ShipName], [t1].[ShipAddress], [t1].[ShipCity], [t1].[ShipRegion], [t1].[ShipPostalCode], [t1].[ShipCountry]
    FROM [dbo].[Orders] AS [t1]
    WHERE [t1].[ShipCountry] = @p1
    ) AS [t2]

The only difference being, Union uses 'UNION' while Concat uses 'UNION ALL'.  A look on W3 Schools gives us the difference between the two keywords.  Union returns distinct values - duplicate rows removed, while UNION ALL selects all the values and doesn't remove any duplicates.  In this example, no duplicates are produced so they return the same result set. However, if we change it to (for example purposes only)

var query = from o in db.Orders
                        where o.ShipCountry == "UK"
                        select o;

var query2 = from o in db.Orders
                        where o.ShipCountry == "UK"                       
                        select o;

Then UNION will return 56 rows, while UNION ALL returns 112 and that is the difference between .Union() and .Concat().

Technorati Tags: , , ,

Visual Studio 2008 Beta 2 Sample Code

Just spotted two downloads for sample code updated for VS 2008 Beta 2.

Samples for Visual Studio 2008 Beta 2 (VB.net)

LINQ and language samples for Visual Studio 2008 Beta 2 (C#)

Lots of different samples here covering both Linq and the core language features. Always something handy to have on your harddrive.

-------

After downloading, I tried to run the C# sample for DynamicQuery and received the following error:

"Failed to generate a user instance of SQL Server due to a failure in copying database files. The connection will be closed."

I changed the query string to be user instance=false which caused a much more helpful error message.

"CREATE DATABASE permission denied in database 'master'.
An attempt to attach an auto-named database for file E:\Users\Ben Hall\Documents\Visual Studio Samples\CSharpSamples\LinqSamples\Data\NORTHWND.MDF failed. A database with the same name exists, or specified file cannot be opened, or it is located on UNC share."

So I changed the query string to use my pre-exiting Northwind Database

"string connString = string.Format("server={0};database=northwind;Integrated Security=SSPI;Connection Timeout=30", sqlServerInstance);"

This change will need to be made to all of the database interacting samples. 

Technorati Tags: , , ,

How Linq knows if a partial method has been implemented

Tuesday, August 07, 2007

My previous post got me thinking, how does the DataContext know if a partial method has been implemented in order to direct the call to the partial method instead of its own internal method?  It's interesting because, if the partial method has not been implemented, all the calls are removed at compile time, and the names of the methods are quite dynamic (InsertObject...(object o)) making it difficult to call this 'known' method.  The methods are defined by the designer, so the internal framework will not know anything about these methods.  While I am taking in terms of how Linq does this, this could be valid for any application.

So, in situations like this there is only one option - Lutz Roeder's Reflector. The Linq implementation is massive and takes a little bit of time to understand how its all been put together.  There is a video by some of members of the Linq team talking about the pipeline processing of Linq to SQL - watch it here

In Linq to SQL, every object returned from the database is tracked by an internal Lookup Table.  There are many reasons why Linq tracks all of the objects, such as caching and change management.  These objects are of type StandardTrackedObject, which inherits from TrackedObject.  If you look in reflector, you will have a list of ways these objects are exposed. 

One of the main ways they are exposed is by a series of methods on the System.Data.Linq.ChangeDirector.StandardChangeDirector object.  Some of the methods are DynamicDelete, DynamicInsert, DynamicUpdate which take a TrackedObject as a parameter.  These methods are used is various places, but one place is within System.Data.Linq.DataContext.ExecuteDynamicUpdate(), there are equivalent delete and insert methods but I will continue to talk in terms of Update.  This means that this method is called to update the object and execute the command against the database.  As mentioned in the last post, this is the method we need to call in order to execute the command within a partial method, so this doesn't decide which method to call.

One of the other places DynamicUpdate is used is by StandardChangeDirector.Update() which in turn is called by ChangeProcessor.SubmitChanges().  This means that when DataContext.SubmitChanges() is called, StandardChangeDirector.Update() is also called later in the process, if updates are required.

StandardChangeDirector.Update() is the important method that decides if the internal ExecuteDynamicUpdate() should be called, or if the call should be passed to the appropriate partial method.

The method checks to see if a property on the TrackedObject is null, this property is called UpdateMethod that returns a Reflection.MethodInfo object.  If it is null, then it calls ExecuteDynamicUpdate() otherwise the method relating to the MethodInfo is invoked using the Invoke command.  Just a bit of background on the MethodInfo object, when using reflection you can access any field or method at runtime without knowing about it at compile time.  The FieldInfo and MethodInfo objects are a bridge between the calling code and the method on the object, by calling MethodInfo.Invoke() the method can be indirectly invoked.  The MethodInfo object would be null, if the method does not exist on the object, or this case if the partial method hasn't been implemented.  This is how Linq can override logic and execute a partial method instead of its own internal method without having to worry if it has been implemented by the developer.

But this still leaves a question unanswered. How does it know the name of the method to execute or even how it finds out if it has been implemented?  The framework knows that each object in a DataContext has three partial methods and the prefix for each of them but not the full name.

The answer is clever, it tries to find the method based on Prefix ("Update") + this.RowType.Name.  RowType.Name is the name of the entity, so if the partial method has been implemented the object will have a method with that name and if its found it will populate the property ready to be invoked, if the method hasn't been implemented, it wouldn't be found and so will be null. 

Simple but really clever!  Hope you found this interesting, I know I did.

Technorati Tags: , ,

Partial Methods on a Linq DataContext

Following on from my previous post and my connect feedback I thought I would write about the partial methods on a linq datacontext. 

As I thought, Dinesh confirmed that the partial methods (Insert, Update, Delete) on a DataContext are overriding instead of notifications.  The reason for this is so that you can override the default logic, so you could redirect the update via a stored procedure.

However, you can continue processing the default way, even within the partial method by calling this.ExecuteDynamicXXXXX() method.

For example, the method below overrides the default UpdateOrder logic, writes out information to the console then continues to execute the update by calling ExecuteDynamicUpdate();

partial class DataClasses1DataContext
{
    partial void UpdateOrder(Order instance)
    {
        Console.WriteLine("UpdateOrder");
        this.ExecuteDynamicUpdate(instance);
    }
}

This is definitely something to be aware of, but the new methods means that it is not a problem if you want to include custom logic but still process the command in the same way.

Re-enabling Intellisense after ReSharper

After installing ReSharper 3.0.2, I decided to disable the Addin while I was using C# 3.0.  However upon disabling it in the Addin manager, I no longer had intellisense.

To re-enable it, go into the Options > Text Editor > C# and tick Auto List Members.  You will then be able to develop again.

image

This is the same for both 2005 and 2008

Technorati Tags: ,

ReSharper and Visual Studio 2008 Beta 2

With every release of Visual Studio, all of the plugin's need to be updated and released.  Over on Ilya Ryzhenkov (ReSharper Product Manager at JetBrains) blog he has posted information on the Early Access Program (EAP) where you can download nightly builds of ReSharper. 

Via the EAP, they have released ReSharper 3.0.2 which includes support for VS 2008 (Orcas) Beta 2.

ReSharper 3.0.2 nightly build

Remove any existing installations before installing.

However, ReSharper doesn't play nicely with C# 3.0 and Linq and the only way to turn it off is to disable the plugin, which also displays it for C# 2.0 which works.

image

Hopefully they will support it soon.  I wonder what DevExpress are doing this C# 3.0....

Technorati Tags: ,

Obtaining table metadata using Linq to SQL - MappingSource

Wednesday, August 01, 2007

One of the posts on the MSDN forum asked how to obtain the type length of a column in the table using Linq, this post will just explain how to obtain this information and some information on the MappingSource object.  When linq does the mappings of database to objects, it transforms the DBType (NVarChar) into a CLR Type (String) which means when you are accessing the objects in code, you are accessing them as .Net types hence no simply way to get the underlying DBType.  One way would be to look the information up in the mappings file or the attribute but Dinesh Kulkarni (PM) pointed out an more directly way, in an indirect way.

The DataContext has a property which allows access to all of the mapping information, this property is Mapping.MappingSource.  The MappingSource object has a property GetModel() which requires the type of the DataContext which contains the table as a parameter. This then returns a MetaModel object which allows you to access some high level information. The method we are interested in is the GetMetaType() which accepts the typeof the entity object we are interested in and returns a MetaType object.  This is when it starts to get interesting.  The MetaType holds information about the table such as associations, DerivedTypes and Inheritance information, but the method we are interested in is GetDataMember() which takes a MethodInfo object relating to the column we want information about. This returns a MetaDataMember which holds all the information about the column, such as if it is a primary key, expression, nullable and DBType.

To demonstrate this in code, first we get the MemberInfo type for the column we are interested in for the GetDataMember method.  Then we can gain the DBType via the MappingSource.

string columnName = "OrderID";
MemberInfo[] mf = Type.GetType("LinqConsole.Order").GetMember(columnName);

db.Mapping.MappingSource
                      .GetModel(typeof(DataClasses1DataContext))
                      .GetMetaType(typeof(Order))
                      .GetDataMember(mf[0])
                      .DbType;

Code isn't that complex, but we can remove the need for obtaining the MemberInfo by going via the DataMembers collection and using a lambda question to return the MetaDataMember for the column name.

string orderIDType = db.Mapping.MappingSource
                                            .GetModel(typeof(DataClasses1DataContext))
                                            .GetMetaType(typeof(Order))
                                            .DataMembers.First(x => x.Name.Equals(columnName))
                                            .DbType;

The DBType in this case is "Int NOT NULL IDENTITY".  For ShipName it comes out as "NVarChar(40)".

Note, when using either of these ways you need to check to make sure that the column actually exists and handle situations when it doesn't correctly.  In this cause, using the first approach might be easier.


Post link:

http://forums.microsoft.com/MSDN/showpost.aspx?postid=1944830&siteid=1

Technorati Tags: ,

Linq To Sql - Peaking under the covers with GetChangeSet, GetCommand, Expression and ToString

In Beta 2, there are a number of ways in which linq allows you to see what it is generating under the covers.   Two new methods, GetChangeSet() and GetCommand(), which replace GetChangeText() and GetQueryText() allow you to interact with changes as objects.  Expression returns the expression tree which has been built for the query, while doing a simple ToString() on a query will return you the T-SQL query.

If we start with the Expression property.  This is a public property on a query var type which displays the expression tree built underneath.

I've created a simple query to return all the orders in the Northwind database.

DataClasses1DataContext db = new DataClasses1DataContext();
var query = from o in db.Orders
                  select o;

For this, query.Expression contains "Table(Order).Select(o => o)".   For more complex queries, then this is really interesting to see what is actually being created.  Take this query:

var query = from o in db.Orders
                   join od in db.Order_Details
                   on o.OrderID equals od.OrderID
                   where od.Quantity > 100
                   select o;

This would be a lot harder to express as a expression tree.  The Expression property for this looks like:

Table(Order).Join(Table(Order_Detail), o => o.OrderID, od => od.OrderID, (o, od) => new <>f__AnonymousType0`2(o = o, od = od)).Where(<>h__TransparentIdentifier0 => (Convert(<>h__TransparentIdentifier0.od.Quantity) > 100)).Select(<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.o)

While not easy to read, you can easily get it to a more readable state:

db.Orders.Join(db.Order_Details, o => o.OrderID, od => od.OrderID, (o, od) => new { order = o, orderDetail = od }).Where(anon => anon.orderDetail.Quantity > 100).Select((anon) => new { order = anon.order, orderDetail = anon.orderDetail });

This is really useful if you are interested in the tree being built and a good learning aid if your interested in what the equivalent tree looks like.  I;m sure there are many other uses by having access to the expression tree.

Moving onto ToString(),  query.ToString() contains the query code which will be executed against the database.  For the simple orders query, it would hold:

SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]

Again, useful when learning and debugging.  However, ToString() is not a great way to get the SQL command.  A better way is to use GetCommand.

GetCommand is a method on a DataContext which takes an IQueryable parameter and returns a DbCommand object.  Once we have the DbCommand object, we can view and edit properties as required.  As this is replacing GetQueryText(), the new command would be:

db.GetCommand(query).CommandText

This returns the same value as ToString - at the moment.  Other properties include, being able to access parameters, the SqlConnection object and transaction object. 

Finally, GetChangeSet() which returns an IList read-only collection of objects which have either been added, modified, or removed since the last SubmitChanges().  The different properties are:

IList<object> queryText = db.GetChangeSet().AddedEntities;
IList<object> queryText = db.GetChangeSet().ModifiedEntities;
IList<object> queryText = db.GetChangeSet().RemovedEntities;

Its a bit of a shame it returns it as object you need to cast it down if you want to do anything with it.  However, as its at the DataContext level it needs to be generic enough to hold every object.   However, it does mean that there is now no way to gain access to the ChangeText query which will be executed - via a property anyway.

Scott Guthrie has also posted how to install the query visualizer for Beta 2 - LINQ to SQL Debug Visualizer which displays the Expression tree and SQL query in its own window.  Interestingly, he has also included the code on how it was created.

Technorati Tags: ,