Blog Bustin' .NET Beats

Summaries of useful and interesting (or not) books, chapters and articles from the web

Multiple Left Joins in Linq to SQL

Posted by blogbustingbeats on 21/10/2009

Had some fun with this – rubbish formatting below – but paste into Visual Studio and autoformat it (ctrl+e+d).

I’ll write some details on this later – but the basic principle is that if you have a nullable foreign key – i.e. you are not sure if you have matches at the end of your table relation and you would normally do a SQL LEFT JOIN, what you need to do in Linq is use the into clause to declare a collection for the results of your join – the reason being that you can then use the DefaultIfEmpty() method in a subsequent from clause to return empty objects where there is no match.
Couple of examples below – first creates a anonymous object on the fly – here you have to null check to set values. The second example beforehand declares a little helper class with Nullable id’s – which gets you round the null checking.
Note that the below uses multiple from clauses to handle the mutiple left join quires (so basically we select from each declared sub-collection).

from p in Persons
    join l in Languages on p.PrimaryLanguageId equals l.Id into tempResult
    join jt in JobTitles on p.JobTitleId equals jt.Id into anotherTempResult    
    from tr in tempResult.DefaultIfEmpty()
    from atr in anotherTempResult.DefaultIfEmpty()    
    orderby p.Id
    where p.Deleted == null
    select new {
        PersonId = p.Id,
        LanguageId = tr == null ? new Nullable() : tr.Id,
        LanguageName = tr.Name,    
        JobTitleId = atr == null ? new Nullable() : atr.Id,
        JobTitleName = atr.Name
    }    

And a more extensive example:

        ///
        /// Person Grid Helper.
        ///
        ///
        /// Linq joins would normally create an anonymous type
        /// – however we cannot use anon types as the grid collection is passed to another method when searching (LoadPersonForSearch).
        ///
        private class PersonGridHelper
        {    
            public int Id { get; set; }
            public string GivenName { get; set; }
            public string FamilyName { get; set; }
            public string OfficeLocation { get; set; }
            public Nullable OfficeLocationId { get; set; }
            public string JobTitle { get; set; }
            public Nullable JobTitleId { get; set; }
            public string Email { get; set; }
            public string EmailDomain { get; set; }
            public int EmailDomainId { get; set; }
            public string AlternateEmail { get; set; }
            public string Mobile { get; set; }
            public string Telephone { get; set; }
            public string Fax { get; set; }
            public string CVFile { get; set; }
            public string ProfilePictureFile { get; set; }
            public string PrimaryLanguage { get; set; }
            public Nullable PrimaryLanguageId { get; set; }
        }

        ///
        /// Loads the main browse grid.
        ///
        public override void LoadGrid()
        {
            IQueryable coll = from person in this.CurrentDataContext.Persons
                                                 join officelocation in this.CurrentDataContext.OfficeLocations
                                                    on person.OfficeLocationId equals officelocation.Id
                                                join jobtitle in this.CurrentDataContext.JobTitles
                                                    on person.JobTitleId equals jobtitle.Id into jobtitles //Nullable FK => left join, DefaultIfEmpty() below
                                                join language in this.CurrentDataContext.Languages
                                                    on person.PrimaryLanguageId equals language.Id into languages //Nullable FK => left join, DefaultIfEmpty() below
                                                join firmemaildomain in this.CurrentDataContext.FirmEmailDomains
                                                    on person.EmailDomainId equals firmemaildomain.Id
                                                from jobtitle in jobtitles.DefaultIfEmpty() //Left join, records from jobtitles collection, if missing default constructor is called
                                                from language in languages.DefaultIfEmpty() //Left join, records from jobtitles collection, if missing default constructor is called
                                                orderby person.FamilyName
                                                where person.Deleted == null
                                                select new PersonGridHelper()
                                                 {
                                                        Id = person.Id
                                                    ,    GivenName = person.GivenName
                                                    ,    FamilyName = person.FamilyName
                                                    ,    OfficeLocation = officelocation.Name
                                                    ,    OfficeLocationId = person.OfficeLocationId
                                                    ,    JobTitle = jobtitle.Name
                                                    ,    JobTitleId = person.JobTitleId
                                                    ,    Email = person.Email
                                                    ,    PrimaryLanguage = language.Name
                                                    ,    PrimaryLanguageId = person.PrimaryLanguageId
                                                    ,    EmailDomain = firmemaildomain.Domain
                                                    ,    EmailDomainId = person.EmailDomainId
                                                 };
                                                 ………………

Posted in .NET, C#, Development, Linq to SQL | Leave a Comment »

T-SQL TO DROP/CREATE IDENTITY SETTING ON ALL TABLES

Posted by blogbustingbeats on 04/10/2009


/*
---------------------------------------------------------------------------------------------------------
PRINTS T-SQL TO DROP/CREATE IDENTITY SETTING ON ALL TABLES

BACKUP BEFORE RUNNING THE GENERATED SQL! - DROPS AND RECREATES EVERYTHING YOU SELECT.
ALSO PLEASE READ THE BELOW - THIS IS A SIMPLIFIED PURPOSE BUILT SCRIPT - YOU WILL NEED TO MODIFY TO YOUR REQUIREMENTS.

THERE IS NO WAY OF REMOVING THE IDENTITY(START, SEED) SETTING ON TABLES -
AND AS IDENTITY INSERT ON/OFF DOES NOT DO THE JOB FOR ALL ORMs (LIKE LINQ FOR EXAMPLE) WE'RE STUCK WITH THE
SQL SERVER MANAGEMENT IDE SOLUTION: CREATE TEMP TABLES - WITH/WITHOUT THE IDENTITY SETTING, MOVE THE DATA, DROP ORIGINAL AND RENAME TEMP TO ORG.

THIS IS A SIMPLIFIED VERSION THAT DOES NOT TAKE INTO CONSIDERATION FKs OR PKs - SCRIPTS TO DROP AND RECREATE THESE ARE AVAILABLE ELSEWHERE
ALSO IT ASSUMES THE PK IDENTITY IS AN INT COLUMN NAMED Id!

SQL2005 AND ABOVE ONLY (SYS VIEWS)

CONFIG:
@ADD_IDENTITY => set to true to ADD this, set to false to REMOVE this.

---------------------------------------------------------------------------------------------------------
*/

DECLARE @ADD_IDENTITY BIT
SET @ADD_IDENTITY = 0 --!!!!! SEE ABOVE!

DECLARE @TABLENAME NVARCHAR(250)
DECLARE @TABLESCHEMA NVARCHAR(250)
DECLARE @TSQL NVARCHAR(MAX)
DECLARE @COLS NVARCHAR(MAX)

DECLARE DBO_TABLE_CURSOR CURSOR

READ_ONLY
FOR SELECT TABLE_NAME, TABLE_SCHEMA
FROM INFORMATION_SCHEMA.TABLES
    WHERE
            TABLE_NAME NOT LIKE 'Version%'
        AND TABLE_NAME NOT LIKE 'sys%'
        AND TABLE_SCHEMA = 'dbo'
        AND TABLE_TYPE = 'BASE TABLE'
    ORDER BY TABLE_NAME

OPEN DBO_TABLE_CURSOR
FETCH NEXT FROM DBO_TABLE_CURSOR INTO @TABLENAME, @TABLESCHEMA
WHILE (@@fetch_status -1)
BEGIN
IF (@@fetch_status -2)
BEGIN
        SET @TSQL = ''
        
        --Get rid of default constraints:
        SELECT @TSQL = @TSQL + '    
        ALTER TABLE dbo.' + @TABLENAME +'
            DROP CONSTRAINT ' + DF.[NAME] + '
        GO' FROM
            SYS.DEFAULT_CONSTRAINTS DF
                INNER JOIN SYS.ALL_COLUMNS AC
                    ON        DF.PARENT_OBJECT_ID = AC.OBJECT_ID
                        AND DF.PARENT_COLUMN_ID = AC.COLUMN_ID
        WHERE OBJECT_NAME(PARENT_OBJECT_ID) = @TABLENAME

        --Create temp table:
        SET @TSQL = @TSQL + '
        
        CREATE TABLE dbo.Tmp_' + @TABLENAME + '
        (
        '        
        SELECT @TSQL = @TSQL + '    [' + COLUMN_NAME + '] ' + UPPER(DATA_TYPE)
            + ISNULL(('(' + CONVERT(NVARCHAR,CHARACTER_MAXIMUM_LENGTH) + ') '), ' ') --Bits and Timestamps have null in all three, something added to null, is null - so we ISNULL check the whole evalutation, and add a space for bits and timestamps.
            + CONVERT(NVARCHAR, REPLACE(REPLACE(IS_NULLABLE, 'YES', 'NULL'), 'NO', 'NOT NULL'))            
            + ISNULL(' CONSTRAINT [DF_' + @TABLENAME + '_' + COLUMN_NAME + '] DEFAULT (' + CONVERT(NVARCHAR, COLUMN_DEFAULT) + ')', '')
            + ',
        '
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE
                TABLE_NAME = @TABLENAME
            AND TABLE_SCHEMA = @TABLESCHEMA
        ORDER BY ORDINAL_POSITION ASC

        --Remove trailing comma:
        SET @TSQL = SUBSTRING(@TSQL, 1, LEN(@TSQL) -5) --remove trailing tabs, linebreak and finally the comma
        
        SET @TSQL = @TSQL + '    
        ) ON [PRIMARY]
        GO'
        
        --So Microsoft seem to have hacked the old NVARCHAR(MAX) - the CHARACTER_MAXIMUM_LENGTH is a int column - so they've added -1 here
        SET @TSQL = REPLACE(@TSQL, '(-1)', '(MAX)')

        --Finally - are we adding or removing the IDENTITY setting?
        IF @ADD_IDENTITY = 1
        BEGIN
            SET @TSQL = REPLACE(@TSQL, '[Id] INT NOT NULL,', '[Id] INT NOT NULL IDENTITY (1,1),')
        END

        PRINT @TSQL -- Half way there! Got temp tables, now let's move the data, drop the original, and rename the temp to replace the original... what could possibly go wrong?
        
        --RESET @TSQL:
        SET @TSQL = '
        IF EXISTS(SELECT * FROM dbo.' + @TABLENAME + ')
        BEGIN '
        IF @ADD_IDENTITY = 1--If so we need to set "IDENTITY_INSERT ON" on the temp tables.
        BEGIN
        SET @TSQL = @TSQL + '    
            SET IDENTITY_INSERT dbo.Tmp_' + @TABLENAME + ' ON'
        END

        --Now get all the column names:
        SET @COLS = ''
        SELECT @COLS = @COLS + '[' + COLUMN_NAME + '],'
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE
                TABLE_NAME = @TABLENAME
            AND TABLE_SCHEMA = @TABLESCHEMA
            AND DATA_TYPE 'timestamp'
        ORDER BY ORDINAL_POSITION ASC
    
        --Remove trailing comma:
        SET @COLS = SUBSTRING(@COLS, 1, LEN(@COLS) -1)
        SET @TSQL = @TSQL + '
            INSERT INTO dbo.Tmp_' + @TABLENAME + ' (' + @COLS + ')
                SELECT ' + @COLS + '
            FROM dbo.' + @TABLENAME + ' WITH (HOLDLOCK TABLOCKX)
        '        

        IF @ADD_IDENTITY = 1 --If we're adding this, then we have switched IDENTITY_INSERT ON - now switch this back off (only one table at any one time in each DB)
        BEGIN
        SET @TSQL = @TSQL + '    
            SET IDENTITY_INSERT dbo.Tmp_' + @TABLENAME + ' OFF'
        END
        
        SET @TSQL = @TSQL + '
        END'

        SELECT @TSQL = @TSQL + '
        DROP TABLE dbo.' + @TABLENAME + '
        GO'
        SELECT @TSQL = @TSQL + '
        EXECUTE sp_rename N''dbo.Tmp_' + @TABLENAME +''', N''' + @TABLENAME +''', ''OBJECT''
        GO'

        PRINT @TSQL
        
END
FETCH NEXT FROM DBO_TABLE_CURSOR INTO @TABLENAME, @TABLESCHEMA
END

CLOSE DBO_TABLE_CURSOR
DEALLOCATE DBO_TABLE_CURSOR

Posted in MS T-SQL | Leave a Comment »

T-SQL Deduplicator

Posted by blogbustingbeats on 25/09/2009


/*
T-SQL DE-DUPLICATER
NOTE THAT THE CURSOR SELECT STATEMENT SELECTS *ALL* THE DUPLICATES
THE CURSOR THEN GIVES YOU ALL THE HIGHEST IDs, i.e. ALL THE LATEST - AND LET's YOU DO SOME ACTION ON THESE
TO SELECT ALL THE OLDEST SIMPLE SWITCH THE IF STATEMENT AROUND
ALSO NOTE THAT YOUR ACTION SHOULD OF-COURSE AFFECT THE CURSOR SELECT STATEMENT
*/
DECLARE @ID INT
DECLARE @ID2 INT

DECLARE DEDUPE_CURSOR CURSOR READ_ONLY
FOR SELECT
T1.[Id], T2.Id AS Id2
FROM [PersonSkill] T1
INNER JOIN [PersonSkill] T2
ON
ISNULL(T1.Deleted,1) = ISNULL(T2.Deleted,1)
AND T1.Skill = T2.Skill
AND T1.Person = T2.Person
AND T1.Id T2.Id
ORDER BY 1

/*
FOR SELECT TABLE_NAME, TABLE_SCHEMA
FROM INFORMATION_SCHEMA.TABLES
*/

OPEN DEDUPE_CURSOR

FETCH NEXT FROM DEDUPE_CURSOR INTO @ID, @ID2
WHILE (@@fetch_status -1)
BEGIN
IF (@@fetch_status -2)
BEGIN

IF @ID2 > @ID BEGIN
PRINT CONVERT(NVARCHAR, @ID2)
--UPDATE [PersonSkill] SET Deleted = GetDate(), DeletedBy = 1 WHERE Id = @ID2
--PRINT 'SOFT DELETED ' + CONVERT(NVARCHAR, @ID2)
END

END
FETCH NEXT FROM DEDUPE_CURSOR INTO @ID, @ID2
END

CLOSE DEDUPE_CURSOR

DEALLOCATE DEDUPE_CURSOR

Posted in Development, MS T-SQL | Tagged: , | Leave a Comment »

T-SQL Foreign Key (FK) Index Creator

Posted by blogbustingbeats on 25/09/2009


/*
FOREIGN KEY INDEX CREATOR

THIS SCRIPT GENERATES SQL TO DROPS AND RECREATE NON-CLUSTERED INDEXES ON ALL FK COLUMNS
SET @FK_PREFIX TO MATCH THE FOREIGN KEY PREFIX IN YOUR DATABASE.

SQL2005 AND ABOVE ONLY (SYS VIEWS)
*/

DECLARE @FK_PREFIX NVARCHAR(50)
SET @FK_PREFIX = 'FK_'

DECLARE @CONSTRAINT_NAME NVARCHAR(255)
DECLARE @TABLE_SCHEMA NVARCHAR(255)
DECLARE @TABLE_NAME NVARCHAR(255)
DECLARE @COLUMN_NAME NVARCHAR(255)

DECLARE FK_INDEX_CURSOR CURSOR READ_ONLY
FOR SELECT
CONSTRAINT_NAME, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE

OPEN FK_INDEX_CURSOR
FETCH NEXT FROM FK_INDEX_CURSOR INTO @CONSTRAINT_NAME, @TABLE_SCHEMA, @TABLE_NAME, @COLUMN_NAME
WHILE (@@fetch_status -1)
BEGIN
IF (@@fetch_status -2)
BEGIN

IF CHARINDEX(@FK_PREFIX, @CONSTRAINT_NAME) = 1 BEGIN
PRINT '

/****** Object: Index [IX_' + @CONSTRAINT_NAME + '] Script Date: ' + CONVERT(NVARCHAR(50), GetDate()) + ' ******/
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N''[' + @TABLE_SCHEMA + '].[' + @TABLE_NAME + ']'') AND name = N''IX_' + @CONSTRAINT_NAME + ''')
DROP INDEX [IX_' + @CONSTRAINT_NAME + '] ON [' + @TABLE_SCHEMA + '].[' + @TABLE_NAME + '] WITH ( ONLINE = OFF )
GO

CREATE NONCLUSTERED INDEX [IX_' + @CONSTRAINT_NAME + '] ON [' + @TABLE_SCHEMA + '].[' + @TABLE_NAME + ']
(
[' + @COLUMN_NAME + '] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO

'

END
END
FETCH NEXT FROM FK_INDEX_CURSOR INTO @CONSTRAINT_NAME, @TABLE_SCHEMA, @TABLE_NAME, @COLUMN_NAME
END

CLOSE FK_INDEX_CURSOR
DEALLOCATE FK_INDEX_CURSOR

Posted in Development, MS T-SQL | Tagged: , , , , , | Leave a Comment »

T-SQL string concatenation without coalesce

Posted by blogbustingbeats on 25/09/2009

Based on: http://msmvps.com/blogs/robfarley/archive/2007/04/08/coalesce-is-not-the-answer-to-string-concatentation-in-t-sql.aspx


SET @COLS = ''
SELECT @COLS = @COLS + '[' + COLUMN_NAME + '] ASC,'
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE CONSTRAINT_NAME = @CONSTRAINT_NAME
ORDER BY COLUMN_NAME DESC

Also poss to use FOR XML PATH:

SELECT ',' + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
FOR XML PATH('')

Posted in Development, MS T-SQL | Leave a Comment »

UNIQUE KEY INDEX AND PRIMARY KEY DROP/CREATE GENERATOR

Posted by blogbustingbeats on 25/09/2009


/*
UNIQUE KEY INDEX AND PRIMARY KEY DROP/CREATE GENERATOR

THIS SCRIPT GENERATES SQL TO DROPS AND RECREATE ALL *PREVIOUSLY DEFINED* UNIQUE INDEXES ON ALL TABLES
SET @FK_PREFIX TO MATCH THE FOREIGN KEY PREFIX IN YOUR DATABASE.

SQL2005 AND ABOVE ONLY (SYS VIEWS)

----------- IMPORTANT CONFIG SETTINGS: ---------------------

SET CONSTRAINT_TYPE:
'UNIQUE'
'PRIMARY KEY'

SET GENERATE_MODE:
1 = DROP
2 = CREATE
3 = RECREATE

------------------------------------------------------------
*/
DECLARE @GENERATE_MODE INT
SET @GENERATE_MODE = 3
DECLARE @CONSTRAINT_TYPE NVARCHAR(25)
SET @CONSTRAINT_TYPE = 'PRIMARY KEY'

DECLARE @CREATE_AS NVARCHAR(25)
SET @CREATE_AS = 'UNIQUE NONCLUSTERED'
IF @CONSTRAINT_TYPE = 'PRIMARY KEY' BEGIN
SET @CREATE_AS = 'PRIMARY KEY CLUSTERED'
END

DECLARE @CONSTRAINT_NAME NVARCHAR(255)
DECLARE @TABLE_SCHEMA NVARCHAR(255)
DECLARE @TABLE_NAME NVARCHAR(255)
DECLARE @COLS NVARCHAR(255)

DECLARE FK_INDEX_CURSOR CURSOR READ_ONLY
FOR SELECT
CONSTRAINT_NAME, TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE
CONSTRAINT_TYPE = @CONSTRAINT_TYPE
AND TABLE_NAME NOT LIKE 'sys%'

OPEN FK_INDEX_CURSOR
FETCH NEXT FROM FK_INDEX_CURSOR INTO @CONSTRAINT_NAME, @TABLE_SCHEMA, @TABLE_NAME
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN

SET @COLS = ''
SELECT @COLS = @COLS + '[' + COLUMN_NAME + '] ASC,'
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE CONSTRAINT_NAME = @CONSTRAINT_NAME
ORDER BY COLUMN_NAME DESC

IF @GENERATE_MODE = 1 OR @GENERATE_MODE = 3 BEGIN
PRINT '
/****** Object: Index [' + @CONSTRAINT_NAME + '] Script Date: ' + CONVERT(NVARCHAR(50), GetDate()) + ' ******/
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N''[dbo].[' + @TABLE_NAME + ']'') AND name = N''' + @CONSTRAINT_NAME + ''')
ALTER TABLE [dbo].[' + @TABLE_NAME + '] DROP CONSTRAINT [' + @CONSTRAINT_NAME + ']
GO
'
END

IF @GENERATE_MODE = 2 OR @GENERATE_MODE = 3 BEGIN
IF @GENERATE_MODE = 2 BEGIN
PRINT '
/****** Object: Index [IX_' + @CONSTRAINT_NAME + '] Script Date: ' + CONVERT(NVARCHAR(50), GetDate()) + ' ******/'
END
PRINT ' ALTER TABLE [dbo].[' + @TABLE_NAME + '] ADD CONSTRAINT [' + @CONSTRAINT_NAME + '] ' + @CREATE_AS + '
(
' +
SUBSTRING(@COLS, 1, LEN(@COLS)-1)
+ '

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
'
END
END
FETCH NEXT FROM FK_INDEX_CURSOR INTO @CONSTRAINT_NAME, @TABLE_SCHEMA, @TABLE_NAME
END

CLOSE FK_INDEX_CURSOR
DEALLOCATE FK_INDEX_CURSOR

Posted in Development, MS T-SQL | Tagged: , , , , | Leave a Comment »

Basics of Linq to SQL Plumbing

Posted by blogbustingbeats on 14/07/2009

A few notes and getting started with Linq to SQL using the O/R Mapper – including a peak at the generated code. We’ll assume VS2008 is used for all this.

So, to start using Linq to SQL I’d recommend adding a new class library to your project and naming it something like BLL or DAL – busines or data access layer, as Linq effectively rolls these to jobs into one you can take your pick on this.

Next  up, to get started add a “Linq to SQL” class to your project using the Add New Item and then look under the Data templates. This will give you a datacontext you can use to update a set of tables, so depending on your needs name this either after your entire database, or give it a name representing a subset of database tables (like UserContext or OrderContext).

Once you have done this, you will see a new .dbml file in your solution, and once this opens you will be looking at the Visual Studio Object Relational Mapper – O/R Mapper for short.

Next step is to test this on some table. Bear in mind that updates and retrieval by default is on a 1-to-1 table basis with the code generated from the O/R Mapper – however, as you will see there are fairly easy ways to extend your classes to be able to load relational data effectively.
In many ways having the 1-to-1 limitation can be seen as a good thing. There are ORM tools out there like EntitySpaces, IronSpeed and many more who will build the whole database in code for you, many-to-many relations and all – however, while it’s nice to auto-generate a complete datalayer with two clicks and a cup of coffee, you can also very easily begin to feel that you don’t really know 100% of what is actually really going on in your application.
And let me just assure you that for a developer – that is not a good thing! If you don’t know how it works, no-one knows how it works.

In contrast to this, Linq to SQL strikes a healthy balance between the convenience of generating classes and a data context (which is easy to query and understand) and leaving the implementation of more advanced features (like retrieving and updating related data) and the core business logic for the developer to implement.

Anyways – moving on. Once you have your O/R Designer window open, get the Server Explorer window up and drill into you database and pick two or three good tables to play around with. Preferably these should be related in the database, and you might also want to add a TimeStamp column to each table (I call mine RowVersion).

First thing to do here is to look at the visual tables in the O/R mapper – check your properties window and see that you have a nice set of data for each one. Note that you have description of the SQL datatype, the matching CLR type, you have null indication, primary key, update checks (check your Timestamp columns! (if you are unfamiliar with timestamps google this, it’s an important SQL feature. Each table can have one Timestamp column (with whatever name you give it) and this is changed every time that row is updated – so it’s a concurrency tool) .
Also note that your relations form the database are displayed with the correct parent/child (PK/FK)  relation.

Next thing you might want to do is save and build, and then grab the full path from the .dbml file tab in Visual Studio and open this file in your favourite text editor (which should of course be the most excellent EditPlus). So here you can see how your SQL tables are described – and note that your relations  are also included in both the FK and PK table.

Next, jump back to VS2008 and have a look at the generated designer.cs class. Here you can see a load of properties, and you should be able to link these back to the information in the .dbml file pretty easily. Don’t worry too much about the details for now.

Next go back to the visual view of the .dbml file in VS2008, right-click one of your tables and choose “View Code” – note that this gives you access to a partial class, that extends the autogenerated class. For now just make a note of this, and realise that this has quite a lot of potential for extending your autogenerated class.

Posted in Linq to SQL | Leave a Comment »

ScottGu’s Linq to SQL Debug Visualizer

Posted by blogbustingbeats on 14/07/2009

From ScottGu’s most excellent blog (http://weblogs.asp.net/scottgu/) you can download a free Visual Studio debugger add-in: the SQL Server Query Visualizer. Follow this thread to install it within your Visual Studio 2008: http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx.

This add-in is really useful because it allows you to check the query syntax built by LINQ before it’s sent to the database. Moreover, it allows you to execute the query from the debugger to discover if the result is what you were expecting. You can also modify the query.

Posted in Linq to SQL | Leave a Comment »

Database Project vs. SQL Server Project in Visual Studio

Posted by blogbustingbeats on 14/07/2009

Just a quick overview of the difference between these two, and a few initial recommendations for their use.

SQL Server Projects are used to create Common Language Runtime (CLR ) User Defined Types (UDT) in SQL Server. Please bear in mind that unless you have a really, really good reason, the almost unanimous advice from SQL Server experts is to leave these well alone.
MS SQL  Server is a pretty advanced product, and you should not have any needs to start extending the set of datatypes available.

Database Projects on the other hand are essential tools for versioning your SQL Server Development. Note that these integrate with your VS IDE – you can for example right click a SQL table in the server explorer and choose to generate create scripts to your Database Project.

Main purpose and benifit of DB Projects is to log all your create and subsequent update scripts in here. Use folders to version these – and to keep the order of execution clear, should you ever need to rebuild your database.

On a wider more general note, this all ties in with a certain style of development, where you might use IDE’s to create, update or drop SQL Server Objects (tables, views, sprocs – whatever) – but you never do anything without creating and saving a script that executes this change using pure SQL.
This is true for both creating, altering and dropping – also make sure all your script have the proper if exists drop etc etc.

For some resources on how to do all this in SQL – we’d recommend reading: Pro T-SQL 2005 Programmer’s Guide from Apress (in general just read stuff from Apress and you’ll be ok!).

Posted in MS T-SQL, Visual Studio | Leave a Comment »

Umbraco Basics: Templates

Posted by blogbustingbeats on 10/07/2009

Right, so this is simple – thou perhaps not as simple in version 4 as in version 3. Main problem is simply just that the main vidoe tutorial on this only covers v3 – where we are dealing with raw HTML templates, whereas v4 now by default comes with support for .NET MasterPages switched on.

So where as the tutorial tells you that Umbraco templates are completely empty and that you can (must) start from scratch – the new v4 in stead comes with something like the below for default:

<%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %>

<asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">

</asp:Content>

So, I thought, well great that makes sense, and proceeded to try and nest another MasterPage below this. Full and nice support for this, but I kept getting this error message:

Cannot find ContentPlaceHolder 'masterContentPlaceHolder' in the master page '/masterpages/Master.master'

So what the heck? Well, of course what I realised (fairly quicly, kinda :0) is that of course these MasterPages are placed inside the Umbraco page engine – which no doubt uses it’s own master page – so you have to realise that you are already in a MasterPage inheritance chain when you define your first base MasterPage.
And what does that mean for us? Well it means that everything has to be wrapped in a Content tag – even from the very first start – to illustrate let me show you my new Base Master and a Home Page template that is nested in this:

<%@ Master Language="C#" MasterPageFile="/umbraco/masterpages/default.master" AutoEventWireup="true" %>

<asp:Content  id="MasterContentPlaceHolder" ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<head></head>

<body>

<asp:ContentPlaceHolder Id="masterContentPlaceHolder" runat="server"></asp:ContentPlaceHolder>

</body>

</html>

</asp:content>

So note that the above is already nested into the Umbraco engine – hence the need for a <asp:content tag at the base level before you can add any HTML.
And so nested within the above I have my child template for the home page:

<%@ Master Language="C#" MasterPageFile="/masterpages/Master.master" AutoEventWireup="true" %>

<asp:Content ContentPlaceHolderId="masterContentPlaceHolder" runat="server">

Home page Template Rules!

</asp:Content>

Hope that makes some sense.



Some other useful and worthwhile features include the ability to insert data from your document types and generic Umbraco fields as well. Us the top buttons to do this.
We will return to this in more detail later.

Posted in Development, Umbraco | Leave a Comment »