Aug 15, 2008

Microsoft SQL Server – nested loops without cursors

I can’t think of a good enough examples on this topic. However, I’ll try to explain.

Let’s say we have 3 tables. Products, Sizes and Items. The Products table holds your products for example - T-Shirt, Shoes and so on. Sizes table holds the sizes for those items - Large, Medium and Small. The Items table holds a combination of valid items - like : Shoes Large, Shoes Small, Shoes Medium and so on.

Let’s say that you have 3 records in the Products table and 3 records in the Sizes table. You need to create all combinations between them (Shoes S, Shoes M, Shoes L …).

So in C# would look like this:

foreach(Record recordProduct in Products)
{
foreach(Record recordSize in Sizes)
{
// Check if the compound record (recordProduct.ProductID,
recordSize.SizeID) exist in Items table
// add it if it doesn't.
}
}

I think most of the developers will use a cursor to achieve this. But I didn’t. I don’t like cursors very much so I tried to do it my own way.

Here are the create scripts for those tables first:

Products:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL
)
ON [PRIMARY]


Sizes:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sizes](
[SizeID] [int] IDENTITY(1,1) NOT NULL,
[SizeName] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL
)
ON [PRIMARY]


And finally, Items:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Items](
[ItemID] [int] IDENTITY(1,1) NOT NULL,
[SizeID] [int] NOT NULL,
[ProductID] [int] NOT NULL
)
ON [PRIMARY]

We want to add all the combinations in the Items table. To make it a bit more complex we would imagine that some of the items will be already generated so prior adding a combination we would like to check if it does not exist.
Here is my script to achieve this:

INSERT INTO Items
SELECT S.SizeID, P.ProductID FROM Sizes S, Products P
WHERE (SELECT ItemID FROM Items WHERE SizeID=S.SizeID AND ProductID=P.ProductID) IS NULL

3 lines of code…
Run it. It should affect some rows when starting it for first time. Run it again, without adding new records to Products or Sizes. It should say: “0 rows affected.”. Now add a product or a size or both. Run again. It will generate the new combinations.

Seems to be fine.

Considerations:
First of all I don’t think you will have to update such table on a daily basis. You may have a table to connect two tables but typically you will not need to generate all possible combinations. You may want to do this if you are updating some database on staging / production server for example.

Second - I am not quite if this approach is faster than the cursors / temp tables or any other approaches you may come up with, so use your head, don’t trust me. I am proven to make fundamental mistakes (see Check if a character is lower case post for reference ;)).

Third - I think you can use this to add another nested loop, so you can have nested loop in a nested loop in a nested loop. Or, with other words, to generate all possible combination between 3 or 4 or even more tables. I can not think of something to stop you doing so.

And last but not least - if you really need to access a combination of two tables, you may consider using view to select them. This way you will not have a physical table to take care of. It’s up to you.

I really love critics, positive or negative ;)

Aug 14, 2008

Skype4COMLib and Blogger - get your posts as a mood text in skype (or do whatever you want with skype ;).

My dear friend Bobby is going on vacation today at 6 p.m. Since I’m going to miss her while she’s taking her vacation on Black Sea I decided to play a bit with Skype4COM and write a small program for her.


This is where everything started ;) (thanks, Bobby for the inspiration ;).
She had her skype mood text set to how many days are until her vacation takes place. I wanted to help her so I wrote a simple tool to countdown until 6 p.m. and change her Skype mood accordingly.

Well I am not going to explain you how I did this. I got better idea later. I decided to make a mood changer for me. The mood changer will take my blogger posts and rotate them as skype mood text.

Skype Mood Text Changer, made with Skype4COM Lib and .NET C#

First of all, where should I get my posts from? Well, there are two ways I can think of. The first one is to use the Blogger API (login with the user, get all user blogs, get all user posts, etc.).
The second one is to use the RSS feed that blogger automatically creates for each blog.
Since this is very small tool I think the first approach is too “heavy” and “complex”. After all we aren’t going to post to the blog or anything that will require us to login in Blogger. So I took the RSS approach.

Let’s see how you can create a small program to do this for you:
1. Start new windows application.
2. Right click your References folder in the solution explorer and choose Add Reference …
3. In the dialog box click on the “COM” tab and find Skype4COMLib.
4. Click OK.

Now you have that skype thing referenced in your project. Add it to your using clause:

using SKYPE4COMLib;

After we are here, and we know we are going to use RSS, we will need Xml namespace as well. Add it too:

using System.Xml;

Okay. In my approach, I wanted to display random post on every 10 seconds. This means I will need to store a post title -> post link pair somewhere. I did this in a generic List of string[] arrays. I am not quite sure how optimized is this but this is only sample and it works fine for me. If you can think of something more optimized - please do not hesitate to write a comment ;). For now, however, add the System.Collections namespace to your using clause:

using System.Collections;

Okay, we have everything we will need to create our small tool. Now add a timer on your form. It’s timer1 in my sample. Set it's interval to 10000 (10 seconds).

Add the following global variables to your project:

List<string[]> posts = new List<string[]>();
private SKYPE4COMLib.Skype skype;

Here is how your Form_Load event should look like:

    
private void Form1_Load(object sender, EventArgs e)
     {
        skype =
new SkypeClass();
        
this.WindowState = FormWindowState.Minimized;
        GetBlogs();
        timer1.Enabled =
true;
     }

What I want you to note in the Page_Load is that I am assigning the skype variable. This way it will remain linked to your skype until the program is runned.

I used routine GetBlogs() in this project, here is it:

private void GetBlogs()
{
XmlDocument docRSS = new XmlDocument();
docRSS.Load(
"http://donchevp.blogspot.com/feeds/posts/default?alt=rss");
    
foreach (XmlNode nodeItem in docRSS.SelectNodes("/rss/channel/item"))
    {
    
string title = nodeItem.SelectSingleNode("title").InnerText;
        
string href = nodeItem.SelectSingleNode("link").InnerText;
posts.Add(
new string[] { href, title });
    }

}


NOTE: replace the url in the docRSS.Load() method, otherwise you will promote my blog ;).

This routine simply takes all the posts and stores them in the List of string arrays as link, title pairs.
Now we need to display the posts as title “-“ link. This will happen in the timer1_Tick event:

private void timer1_Tick(object sender, EventArgs e)
{
int iPostIndex = int.MinValue;
    
if (posts.Count > 0)
    {
    
Random rnd = new Random();
        iPostIndex = rnd.Next(0, posts.Count);
        skype.CurrentUserProfile.MoodText = posts[iPostIndex][1] +
" - " + posts[iPostIndex][0];
}
}

Everything seems to work fine now. Run your program. Skype should ask you if you are sure you want to give access to this program to use skype. Agree with that. You should now see your posts rotating each 10 seconds.

Here is the complete code (I will also upload the project on Chameleon Bulgaria site, as codes in Blogger doesn’t appear very smoothly):

Form1.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SKYPE4COMLib;
using System.Xml;
using System.Collections;

namespace dayOffCounter
{
  
public partial class Form1 : Form
   {
    
List<string[]> posts = new List<string[]>();
    
private SKYPE4COMLib.Skype skype;
    
public Form1()
     {
        InitializeComponent();
     }

    
private void Form1_Load(object sender, EventArgs e)
     {
        skype =
new SkypeClass();
        
this.WindowState = FormWindowState.Minimized;
        GetBlogs();
        timer1.Enabled =
true;
     }

    
private void GetBlogs()
     {
        
XmlDocument docRSS = new XmlDocument();
        docRSS.Load(
"http://donchevp.blogspot.com/feeds/posts/default?alt=rss");
        
foreach (XmlNode nodeItem in docRSS.SelectNodes("/rss/channel/item"))
        {
          
string title = nodeItem.SelectSingleNode("title").InnerText;
          
string href = nodeItem.SelectSingleNode("link").InnerText;

           posts.Add(
new string[] { href, title });
        }
     }

    
private void timer1_Tick(object sender, EventArgs e)
     {
        
int iPostIndex = int.MinValue;
        
if (posts.Count > 0)
        {
          
Random rnd = new Random();
           iPostIndex = rnd.Next(0, posts.Count);
           skype.CurrentUserProfile.MoodText = posts[iPostIndex][1] +
" - " + posts[iPostIndex][0];
        }
     }
   }
}

Things to consider: Unfortunately skype has some constraints we can not avoid. First of all - the text seems to be too short to hold some of my posts, which results in links not being rendered correctly and leading to a wrong page (or even worse - to a page that doesn’t exist). I really wish to be able to set click here links as a mood text but it is not possible for now (at least I couldn’t find such functionality).

Happy codding!

Skype4COM Lib - how to register Skype ?


I wrote few tools, which only worked on my computer and not on the computer of my collegue - Bobby. She was having newer version of Skype and in the beggining I assumed it is a protocol problem. It finally appeared that the problem is her computer not having Skype4COMLib registered. So if you run in such a trouble, do the following :

1. Find the Skype4COM.dll file on your computer (typically it is in : C:\Program Files\Common Files\Skype)
2. Go to your Start Menu -> Run ...
3. Type cmd
4. In the command prompt type : regsvr32 Skype4COM.dll or "regsvr32 C:\Program Files\Common Files\Skype\Skype4COM.dll" depending on in which directory you are with the cmd (note the quotes that surround the path ;) ...


Everything should be fine now.

NOTE: I am writing this post not because it is something complex, but because I often forget how to register something ... Especially Skype :). Now I (and you) will have a reference, so don't be shy, add this post to your bookmarks :P

P.S. I hope I will be able to write a small tool to register Skype4COMLib

Jul 25, 2008

Microsoft SQL - you can ommit the INTO clause in insert statement?

I am not quite sure if this is a known feature / bug, but it is possible to write

INSERT Products (ProductName)
VALUES ('TestProduct')

instead the "standard":

INSERT INTO Products (ProductName)
VALUES ('TestProduct')

I repeat, I am not quite sure if this is standard behaviour for Microsoft SQL Server, and for which versions. I am not quite sure even if it is valid for all INSERT scenarios you may face, but I tried few different scenarious which include insertion of rows and it works like charm.

Note: I will suggest you to stick with the
INSERT INTO as it seems "more standard" to me. Furthermore if you are using some tools to do some SQL work (tools which may need to parse your
SQL) you will probably need to change back to INSERT INTO if you have used INSERT.

Nice TFS Query

I needed to find all my tasks I had closed, but I hadn't added time input for.
I was thinking how can I sort all my TFS tasks to achieve this and it appeared to be very strightforward.

Here is what you should do:

TFS Query to get all closed tasks without working hours.

In other words you are saying :

Your new TFS query will look like this.

"Give me all the work where the completed work is 0 hours, the state is closed and it is assigned to me."

After you save and give a name to your TFS query, you will find it under the "My Queries" node in your Team Explorer window:

>

Jul 17, 2008

Code Policies - the first step to get rid of boring code policy violations is made.

As I and Vesko (only!) discussed - it is great to follow code policies, and they are saving time. A lot of time. I agree.
I really like to have so strict policies at work so I can find for example the ObjectDataSource of some dropdown, without knowing its name. For example i will type "objDsSomething" or "odsSomething" or "ODSSomething". It really saves time.

I don't really agree with Vesko's opinion that only in the begining you are violating the code policies. I think even developers who worked on the same project for year will violate its policies (not so often offcourse).

The problem is that we are all human beings and we all make mistakes. I decided to do something to help myself get rid of at least the boring code policies - such
as naming conventions.
Here is what I have so far (I started this thing few days ago and I am working on it for about an hour daily after I was all day at work so it may not look very promising but I think it has potential):



When you click on "Validate Current Document" the document which is currently open will be validated against predefined naming conventions. If you violated something you will have this output:



I have few more problems to solve and will be really glad if someone can point me the direction:

1. I need to find a way to add this menu to the context menu for the document and also I would like to add hot key so you can for example validate the document by pression "CTRL + V + D" or something else (this is low priority).
2. I would also like to be able to check the code itself for inadequate assignments, method calls and so on. The CodeModel approach I think, will not allow me to do so.
3. I would like to change those standard icons with custom ;) (low priority).

Currently this thing can fly only for naming conventions.

Jul 15, 2008

C# standard way to check if a character is lower case

Okay, I am guilty ;). I found the "C# way", I forgot to check the char to see if it offers some static methods to check if a character is lower case. IT DOES :). I ovelooked it... Here is how will you check if a character is lower case in "C# style":

char.IsLower(c);

Furthermore the char type offers more useful methods as : .IsUpper(char c) ;). IsNumber, IsPunctuation and so on, so I will stick to it for now. Sorry for misleading you (if I did :)
.

Check if a character is lower case (C#)

I am not quite sure if there is a "standard" way to check if a character is lower case but here is what I came up with:

private bool isLowerCase(char c)
{
  
return c > ((int)'a') - 1 && c < ((int)'z') + 1;
}

I think another approach would be to check if the character against the lowercase version of the character but this way you will have to first convert it to string (as the char type doesn't support .ToLower()), then to get the element at index 0 (so you again have a char variable. Here is the method to do so:

private bool isLowerCase(char c)
{
return c.ToString().ToLower()[0] == c;
}

the last approach is to check the character with regular expression:

private bool isLowerCase(
style="color:Blue;">char c)
{
return Regex.IsMatch(c.ToString(), "[a-z]");
}

Note that I haven't tested those approaches, I only worked with the first one, the other were written just to point you other approaches. If you want to use some of them you will need first to test them (although I think they will also work like charm). The other think to consider is the performance, when I have some free time I may perform some tests to see which approach is the fastest.

Jul 14, 2008

C# SqlParameter strange behaviour (or not so strange?)

I had strange experience with the SqlCommand.AddWithValue method.
Consider the following code:

SqlCommand cmd = new SqlCommand();
cmd.CommandText =
"SELECT * FROM Products WHERE ProductID=@ProductID "+
cmd.Parameters.AddWithValue(
"@ProductID", 12);

Can you spot error?
It is a developer error ;). The problem is the "+" after the command text line.
What is strange is that it won't generate compiler error. Instead this, the text will become:

"SELECT * FROM Products WHERE ProductID=@ProductID @ProductID"

(the name of the variable added will be appended to the command text)
Offcourse in the normal case you will not have + between the CommandText = and Parameters.AddWithValue, but if
you accidently miss this tiny error
it will be pretty hard to spot it later (as the compiler will not complain).


Be careful ;)

Jul 13, 2008

Code policies?

I was thinking the other day about how much efforts does it take to strictly follow your company code policies.
They are saving time for sure, but they are also wasting time.

First of all the developer needs to think about the policies all the time. This districts him/her from the real problems.
Second - after the task is completed the developer again needs to check if his / her code follows the code policies.
Third - if there is a code review - the code reviewer will also need to check if there isn't a problem with those code policies, class by class, member by member.

Some of the rules are very very foundamental as for example not to reference the DataAccess Layer from the User Interface Layer.
Other are company level rules - such as
naming conventions, using some classes on some places and not using some classes on some places. Also - using your project util classes instead implementing the same functionality in your class.

While some of the things aren't very easy to note in a code, other are obvious. And while some of the things aren't very easy to automate via AddIn or external program, other can be easilly automated.

In my opinion the developer should be focussed develop some more useful functionality, instead thinking about which rule will he / she broke.
Please note that by writing the above sentence I am not saying - "Drop the code policies!", but "Automate the code policies!". If I had some tool to check if I violate a rule while writing code, I will rewrite my code in order to satisfy this rule. But after I don't have I need to think about those rules while developing, which districts me from what I need to achieve.

I would really appreciate if you drop a comment on the following question(s):

"Does the code policy bother you? Does it take from your time? Does it districts you?"

Thanks in advance!

Jul 10, 2008

C# Microsoft Excel Automation - very simple Microsoft Excel AddIn to get Amazon deals

First of all here is how will it look:



This is a Microsoft Excel 2003 Addin Project (under File -> New -> Project expand C# -> Office and you should see it).

Here is the code for the addin connection :

XmlDocument doc = new XmlDocument();
// Link to the Amazon feed.
doc.Load("http://rssfeeds.s3.amazonaws.com/goldbox");
XmlNodeList xmlNodeItems = doc.DocumentElement.SelectNodes("/rss/channel/item");

Excel.
Worksheet sheet = (Excel.Worksheet)Application.ActiveSheet;

int i = 0;
// Start reading each item in the rss feed.
foreach (XmlNode
xmlNodeItem in xmlNodeItems)
{
i++;
if (i > 10) break;
// Get title, link and description, the
// description will be later used to retrieve image url.
string strTitle = xmlNodeItem.SelectSingleNode("title").InnerText;
string strLink = xmlNodeItem.SelectSingleNode("link").InnerText;
string strDescription = xmlNodeItem.SelectSingleNode("description").InnerText;

// Get the cell in which we will write the title of the product.
Excel.Range rngTitle = ((Excel.Worksheet)Application.ActiveSheet).get_Range("A" + i.ToString(), "A" + i.ToString());

// Some variables for the picture creation:

float picLeft = 50;
float picTop = float.Parse(rngTitle.Top.ToString()) + 5f;
float picWidth = 50;
float picHeight = 50;
string strImageFile = GetImageUrl(strDescription);


// Make fonts bold and write the text in the first cell ("A").
rngTitle.Font.Bold = true;
rngTitle.Value2 = strTitle;

// Add the picture
Excel.Shape pic = ((Excel.Worksheet)Application.ActiveSheet).Shapes.AddPicture(strImageFile, Microsoft.Office.Core.MsoTriState.msoCTrue, Microsoft.Office.Core.MsoTriState.msoCTrue, picLeft, picTop, picWidth, picHeight);

// Make the title centered both horizontally and vertically.

rngTitle.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
rngTitle.VerticalAlignment = Excel.
XlVAlign.xlVAlignCenter;

// Make the picture move if neighbour cell is resized.
pic.Placement = Microsoft.Office.Interop.Excel.XlPlacement.xlMove;
}

Note : I removed the VSTO generated code region so I don't waste space. You shouldn't do this ;).

In other words if you copy the code you will need to paste it below the VSTO generated code region.

I also used a subroutine to extract the image url from the description, it is very simple, greedy regular expression:

    
private string GetImageUrl(string strDescription)
     {
        
Match mImage = Regex.Match(strDescription, "src=\".+?\"");
        
return mImage.Value.Replace("src=", "").Replace("\"", "");
     }


Things to do:

1. First of all there is no good way to resize a cell in Excel. Your user will be presented very ugly screen. Here is how it actually looks if you don't resize the cells:




Very ugly huh?

2. The other think that bothers me is that Amazon lists about 100 products in their deals feed. So it is a bit slowly to get all the images (they are downloaded on the fly).

I will be very happy to discuss this problem with any of you.

Cheers ;).


Jul 8, 2008

3 ways to get true / false as string in C#

Who needs that much? Well, it's good to choose one and keep up with it.

The first, oldfashioned way is to write the bool as string:

string trueStr = "True";

But how would you know if the first letter should be uppercased?


There are two better ways to get the True string or False string:

string trueStr = true.ToString();
string trueStr = false.ToString()

And the last method is to use the bool type :

string trueStr = bool.TrueString;
string trueStr = bool.FalseString;

I think it is best to use the last one as it seems to me it was added exactly for such purposes.
>

Jul 4, 2008

button click and onclientclick event execution order

I was looking at the Google analytics service I have installed on this blog, there is a section in which you can find top search queries which users used to reach my blog.

And the title of this post appeared in the results. I decided to post a short answer to this question.

The answer is that button click executes first on the client side and then, if the execution returns true or void - a post back is invoked using __doPostBack with a parameters to let the server know it needs to invoke the button OnClick event handler. Prior the OnClick handler is invoked, the server will invoke the OnLoad event handler for the page, setting Page.IsPostBack to true.

>

Jun 26, 2008

C# filtering List of abstract objects to a List of concrete objects (is vs. as vs. OfType + ToList()).

In many cases we may want to extract a list of concrete object types from a list with more abstract types.

For example if we have a List of users, we may want to extract another list of users which are administrators (let’s suppose administrator inherits user).

I did some very basic tests to check which approach will be faster to achieve this (by faster I mean optimized, not faster to write). I used a List with 10,000,000 elements of type object, filled with int objects and string objects. The goal was to retrieve a Lits of int objects only, as fast as possible.

For now I have 3 candidates to do this (if you know more - please write a comment):

Candidate 1 : Iterate the collection with foreach, get each element as object, cast this
element to nullable int (int?) (using “as” operator) and see if it is null.
Candidate 2 : Iterate the collection with foreach, get each element as object and check it with “is” operator against int type.
Candiate 3 : Use OfType with ToList, which is only one line of code.

Let’s see the classes (I did a separate class for each approach)

class ISSample
{
public static void StartSample(List<object> objects)
    {
        
int processed = 0;
        
List<int> intList = new List<int>();
        
long ticksStart = DateTime.Now.Ticks;
        
foreach (object obj in objects)
        {
           processed++;
          
if (obj is int)
           {
             intList.Add((
int)obj);
           }
        }
    
long ticksEnd = DateTime.Now.Ticks;
double result = Convert.ToDouble(ticksEnd - ticksStart) / TimeSpan.TicksPerSecond;
        
Console.WriteLine("IS executed for : " + result.ToString("N10")
+
" seconds, items processed: " + processed);
}
}

class ASOperatorSample
{
public static void StartSample(List<object> objects)
    {
    
int processed = 0;
        
List<int> intList = new List<int>();
        
long ticksStart = DateTime.Now.Ticks;

        
foreach (object obj in objects)
        {
           processed++;
          
int? obj2 = obj as int?;
          
if (obj2 != null)
           {
             intList.Add((
int)obj2);
           }
        }

        
long ticksEnd = DateTime.Now.Ticks;
double result = Convert.ToDouble(ticksEnd - ticksStart) / TimeSpan.TicksPerSecond;
Console.WriteLine("AS executed for : " + result.ToString("N10") + " seconds items processed: " + processed.ToString());
     }
   }

class OfTypeSample
{
public static void StartSample(List<object> objects)
    {
    
List<int> intList = new List<int>();
        
long ticksStart = DateTime.Now.Ticks;

        
// Here is how this is done in C# 3.5 style
        // with one line only
        intList = objects.OfType<int>().ToList<int>();
        
        
long ticksEnd = DateTime.Now.Ticks;
        
double result = Convert.ToDouble(ticksEnd - ticksStart) / TimeSpan.TicksPerSecond;
        
Console.WriteLine("OfType executed for : " + result.ToString("N10") + " seconds.");
}
}


Now let’s see some outputs:

AS executed for : 5.3281250000 seconds items processed: 10000000
IS executed for : 0.3750000000 seconds, items processed: 10000000
OfType executed for : 0.7812500000 seconds.
Press any key to continue . . .

AS executed for : 5.6562500000 seconds items processed: 10000000
OfType executed for : 0.7812500000 seconds.
IS executed for : 0.5312500000 seconds, items processed: 10000000
Press any key to continue . . .

OfType executed for : 0.9375000000 seconds.
AS executed for : 5.5468750000 seconds items processed: 10000000
IS executed for : 0.3906250000 seconds, items processed: 10000000
Press any key to continue . . .

As you can see there is slight difference in the results depending on which approach will we call first. The obvious thing is that Is operator is always faster, followed by the OfType and the last place is for AS operator.

You may note that for the “is” and “as” operators I added “items processed:” portion. This is very important - by using foreach you can do some statistics inside the loop, while using OfType won’t let you write any code inside the loop.

Jun 25, 2008

C# var - the difference between invariant type (JavaScript and other languages) and C#

The var keyword in C# (which is not even a keyword as you are permitted to create a class "var") is different from javascript.
The difference is that once assigned, a variable pefixed with a var "keyword" will have the type of what was assigned and will only allow you to assign object of the same type to this variable (or objects which inherit from that object).

Here is a brief example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;

namespace LINQ
{
  
class Program
   {
    
static void Main(string[] args)
     {
        Sample();
     }
    
static void Sample()
     {
        
style="color:Blue;">var a = new object();
        a =
new OperationCanceledException();
        
Console.WriteLine(a.GetType().Name);
     }
   }
}

Note, that we first assign new object to the variable a. After this assignment, "a" will only accept variables of type object (or any other type, which inherits from object). Then we assigned OperationCanceledExceptionObject (which inherits object type through Exception). If you try the opposite - to first assign
OperationCanceledException variable and then object you will end up with exception.


Conclusion: with var you are forcing the compiler to infer the type of the right side variable automatically. You will not need to declare what the type of variable should be. This saves you the following:

object a = new object();

What's nice is that Microsoft Visual Studio 2008 will be able to determine the type of a also and offer you intelisense.

May 28, 2008

How to catch specific MSSQL exception in .NET?

This one is pretty interesting. Not quite sure how useful, but it is good to know it.

For the following example you will need one SQL table. I have a table called products. It has a column ProductName (NVARCHAR(10)), which we will use so I can show you how to catch specific SqlException and pass over all other SqlExceptions (actually re-throw them).



As you may or may not know the Sql namespace has one exception which is generic and is thrown no matter what caused the exception inside the SqlServer, .NET will always throw SqlException.



So how can we distinct the different Sql Errors?

Let’s make a short demo so I can show you. First of all, as I said, we will have a table (in my case Products).

The ProductName column is set to be
unique, so if a product with the same name already exist in .NET we will have SqlException, but in Sql the things are different. There we will have something like:



Msg 2627, Level 14, State 1, Line 1

Violation of UNIQUE KEY constraint 'p'. Cannot insert duplicate key in object 'dbo.products'.



Let’s say we want to catch only the “Unique violation” exception and leave all other exceptions propagate.



Let’s setup a very small form to illustrate this. We will have two labels, one text box and one button. When clicking on the button the text in the text box will be added in the Products table. If there is already product with the same name we will display the second label.

Simple isn’t it?



Here is the form:



<asp:Label ID="lblProductNameCaption" runat="server" Text="Product name:" />

<
br />

<
asp:TextBox ID="txtProductName"

         runat="server"

Width="259px">

asp:TextBox>

<
br />

<
asp:Label ID="lblError"

runat="server"

        
Visible="false"

        
ForeColor="red"

        
Font-Size="x-small">

asp:Label>

<
br />

<
asp:Button ID="btnSaveProduct"

        
runat="server"

        
OnClick="btnSaveProduct_Click"

        
Text="Save"

Width="79px" />



In order to distinct the unique constraint violation we need to compare it to something. Fortunately SqlException type transports the ErrorNumber from the SqlServer straight to .NET, so we can use it.

We need to find out the number for that particular exception. In a previous post I wrote where can you obtain information about all errors in Sql Server.

Okay, we know the error number of Unique Constraint Violation.

Let’s write some code to handle it:



const int uniqueConstraintViolaton = 2627;



This constant you may define as global so you can access it across your code.



The magic comes in the
btnSaveProduct_Click:



SqlConnection con = new SqlConnection("connection_string");

con.Open();

SqlCommand cmd = con.CreateCommand();

cmd.CommandText =
"Insert into products " +

"(productname)" +

            
"values " +

            
"('" + txtProductName.Text + "');";

try

{

cmd.ExecuteScalar();

}

catch (SqlException sqlException)

{

if (sqlException.Number == uniqueConstraintViolaton)

    {

    
this.lblError.Text = "Product already exist.";

        
this.lblError.Visible = true;

     }

    
else

     {

    
// Pass over ...

        throw sqlException;

     }

}



What we did? We caught SqlException in the
catch block.

We tested if it is the Sql error we are expecting. If it was - we performed some actions to inform the user.

If it wasn’t - we re-thrown, so if there is some exception handling code - it could receive it and handle it as expected.



When you type in a name of a product which already exist in the database you should see the label showing, informing you that there is a product with that name.

To test if other exceptions are propagating, you may type a name with more than 10 symbols (I set my ProductName column to be NVARCHAR(10)). You should see exception which informs you that the data would be truncated. Your code will not handle this, but pass it over.




Literature which may be useful: Microsoft SQL Server 2005 Unleashed, Microsoft SQL Server 2005 For Dummies, Pro ADO.NET 2.0, Programming Microsoft® ADO.NET 2.0 Core Reference

How to get all Microsoft SQL Server errors

This can be achieved by using the sys.sysmessages system view. You may want to specify language to prevent errors localized in all available languages to be returned.
English should be with 1033 id.

Here is a query which will return all the errors for English:

select * from sys.sysmessages where msglangid=1033


Literature which may be useful: Microsoft SQL Server 2005 Unleashed, Microsoft SQL Server 2005 For Dummies
>

May 26, 2008

Enumerators - the correct way to parse an enumerator.

First of all - what are enumerators?

You can think for the enumerators as for some kind of constants. They are used to check objects against.

Let's say you will have the following dropdown:



<asp:DropDownList ID="ddlGender" runat="server">

<asp:ListItem Value="1">Maleasp:ListItem>

<asp:ListItem Value="2">Femaleasp:ListItem>

<asp:ListItem Value="3">Won't shareasp:ListItem>

asp:DropDownList>



As you know the genders won't ever change, for code convenience, you may want to define an enumerator to hold them, so you can check against:



enum EnumUserGender

{

Male = 1,

Female = 2,

Unknown
= 3

}



This way, the Male element of the enumerator will have a value of 1, Female will have a value of 2 and Unknown will have a value of 3.

To check a value against enumerator you may do the following:



int Gender = 1;

if (Gender == EnumUserGender.Male)

{



}



In this case the if will evaluate to true, as the Gender variable has a value of 1.



Now, let's return to our case with the
asp:DropDownList, we want to be able to know which asp:ListItem was selected by the user. We don't want to convert the value to int first, but to receive it as a EnumUserGender variable. Let's do this in the SelectedIndex SelectedIndexChanged asp:DropDownList:



protected void ddlGender_SelectedIndexChanged(object sender, EventArgs e)

{

EnumUserGender genderSelected = (EnumUserGender)Enum.Parse(typeof(EnumUserGender), ddlGender.SelectedValue, true);

switch (genderSelected)

{

case EnumUserGender.Male:

Response.Write(
"Check our cars section!");

break;

case EnumUserGender.Female:

Response.Write(
"Check our make-up section");

break;

case EnumUserGender.Unknown:

Response.Write(
"If you want you can check either our cars section or our make-up section");

break;

default:

Response.Write(
"Sorry, there was an" +

"error, please go back and try again," +

" the error was logged and will be reviewed by our team.");

break;

}

}

}



What we did was to actually Parse the
Enum , by using its base class method Parse. It recieves 2 parameters + 1 optional:



Parameter 1 is of type
Type, this is the type to which the enumerator will be parsed / converted. In our case we use the typeof, function, passing our enum type as a paramter.

Parameter 2 is of type
string, this is the value to be parsed.

Parameter 3 is of type
bool, and indicates whether the value passed as a string should match case sensitive. If set to true, you will have insensitive Parse, so "mALe" will be parsed correctly.