Feeds:
Posts
Comments

Archive for the ‘C#’ Category

POCO Object Creation

Updated!
And again! I just can’t leave well enough alone, can’t I?

I really like the Microsoft’s MVC and Entity Frameworks, and their use of Plan Ol’ C Objects (often just called POCO objects, and yes, I know that ‘objects’ is completely redundant) for data interactions. They’re simple to code, perform pretty well and most importantly, are easy to understand. However, I always run into a problem when starting a new project. Personally, I’m a database first kind of guy. I create the database, develop the initial schema and once that’s settled, I’m ready to start the code. This is completely the opposite of the Code First tooling in Visual Studio. If you do the Code First, you only create one set of objects in code and the tooling creates the database for you. But, in my case, I’ve already created the database – so what to do?

Create your own POCO generator is what. This is a pretty simple-minded POCO generator. It takes in a table name as a parameter and it’s output is a valid C# object. That said, it does cover a lot of possibilities, trying to generate as thorough of an object as possible.

drop procedure generatePOCO
go

create procedure generatePOCO @tablename sysname
as
begin
	-- Class declaration
	select
		'[Table("' +  @tablename + '")]' + char(13)
		+ 'public class ' + @tablename + char(13)
		+ '{'

	-- create a property with annotations for each column
	union all
	select
		-- key attribute
		case
			when 'ID' = UPPER(columns.name) or 
			(
				'_ID' =  RIGHT(UPPER(columns.name), 3) and 
				not exists (select 1 from sys.all_columns where object_id(@tablename) = all_columns.object_id and UPPER(name) = 'ID')
			) 
			then char(9) + '[Key]' + char(13)
			else ''
		end +

		-- hide "id" type fields using hidden attribute
		case
			when 'ID' = UPPER(columns.name) or '_ID' =  RIGHT(UPPER(columns.name), 3)  
			then char(9) + '[HiddenInput(DisplayValue=false)]' + char(13)
			else ''
		end +

		-- identity delcaration
		case
			when is_identity=1 then char(9) + '[DatabaseGenerated(DatabaseGeneratedOption.Identity)]' + char(13)
			else ''
		end +

		-- maxlength attribute
		case 
			when t.name like '%char%' and -1 <> max_length then char(9) + '[MaxLength(' + cast(max_length as varchar) + ')]'+char(13)
			else '' 
		end +
	
		-- default value attribute
		case
			when definition is not null then char(9) + '[DefaultValue' + REPLACE(definition, '''', '"') + ']' + char(13)
			else '' 
		end +
	
		-- Required for not nullable
		case
			when 0 = is_nullable then char(9) + '[Required]' + char(13)
			else ''
		end +

		-- No special characters
		case 
			when t.name like '%char%' and -1 <> max_length then char(9) + '[NoSpecialCharacters]'+char(13)
			else '' 
		end +
	
		-- property declaration
		REPLACE(
			char(9) + 'public '+
			case
				when t.name = 'bigint' then 'Int64'
				when t.name = 'bit' then 'Boolean'
				when t.name = 'date' then 'DateTime'
				when t.name = 'datetime' then 'DateTime'
				when t.name = 'datetime2' then 'DateTime'
				when t.name = 'datetimeoffset' then 'Datetimeoffset'
				when t.name = 'decimal' then 'Decimal'
				when t.name = 'float' then 'Double'
				when t.name = 'int' then 'Int32'
				when t.name = 'money' then 'Decimal'
				when t.name = 'numeric' then 'Decimal'
				when t.name = 'real' then 'Single'
				when t.name = 'smalldatetime' then 'DateTime'
				when t.name = 'smallint' then 'Int16'
				when t.name = 'smallmoney' then 'Decimal'
				when t.name = 'sql_variant' then 'Object*'
				when t.name = 'time' then 'TimeSpan'
				when t.name = 'tinyint' then 'Byte'
				when t.name = 'uniqueidentifier' then 'Guid'
				when t.name = 'xml' then 'Xml'

				when t.name like '%char%' then 'String'
				when t.name like '%text%' then 'String'
				else 'byte[]'
			end +
			case when is_nullable = 1 then '?' else '' end +
			' '+
			columns.name+
			' { get; set; }',
		'String?','String') -- replace is done since String doesn't need a '?' to allow nulls

		-- terminal <cr>
		+ char(13)
	from sys.all_objects tables
	inner join sys.all_columns columns on columns.object_id = tables.object_id
	inner join sys.systypes t on t.xusertype = columns.system_type_id
	left outer join sys.default_constraints dc on dc.name = OBJECT_NAME(default_object_id)
	where tables.name = @tablename

	-- commentary
	union all
	select char(9) + '// Foreign keys from this table to a master table' + char(13)

	-- foreign keys referenced from this table to another
	union all
	select 
		-- required attribute as this is the dependant key
		char(9) + '[Required]' + char(13) + 
		
		-- foreign key column declaration
		char(9) + '[ForeignKey("' + all_columns.name + '")]' + char(13) +

		-- foreign key declaration
		char(9) + 'public virtual ' + OBJECT_NAME(referenced_object_id) + ' ' + OBJECT_NAME(referenced_object_id) + ' { get; set; }'
	from sys.foreign_key_columns
	inner join sys.all_columns on all_columns.object_id = parent_object_id and all_columns.column_id = parent_column_id
	where OBJECT_ID(@tablename) = parent_object_id

	-- commentary 
	union all
	select char(9) + '// Foreign keys to this table from other tables' + char(13)
	
	-- foreign keys to this table from other tables
	union all
	select char(9) + 'public virtual ICollection<' + OBJECT_NAME(parent_object_id) + '> ' + OBJECT_NAME(parent_object_id) + ' { get; set; }'
	from sys.foreign_key_columns
	where OBJECT_ID(@tablename) = referenced_object_id

	-- close out class
	union all
	select '}' + char(13)
end
go

The output will look something like:

[Table("UserProfile")]
public class UserProfile
{
	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	[Required]
	public Int32 UserId { get; set; }

	[MaxLength(112)]
	[Required]
	[NoSpecialCharacters]
	public String UserName { get; set; }

	[MaxLength(500)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessEmail { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String FullName { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessName { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessAddress1 { get; set; }

	[MaxLength(100)]
	[NoSpecialCharacters]
	public String BusinessAddress2 { get; set; }

	[MaxLength(100)]
	[NoSpecialCharacters]
	public String BusinessAddress3 { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessCity { get; set; }

	[MaxLength(4)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessState { get; set; }

	[MaxLength(20)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessZip { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String BusinessPhone { get; set; }

	[MaxLength(100)]
	[NoSpecialCharacters]
	public String BusinessFax { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String PasswordQuestion { get; set; }

	[MaxLength(100)]
	[Required]
	[NoSpecialCharacters]
	public String PasswordAnswer { get; set; }

	// Foreign keys from this table to a master table

	// Foreign keys to this table from other tables

	public virtual ICollection<webpages_UsersInRoles> webpages_UsersInRoles { get; set; }
}

for a parent table and for a child table:

[Table("webpages_UsersInRoles")]
public class webpages_UsersInRoles
{
	[Required]
	public Int32 UserId { get; set; }

	[Required]
	public Int32 RoleId { get; set; }

	// Foreign keys from this table to a master table

	[Required]
	[ForeignKey("UserId")]
	public virtual UserProfile UserProfile { get; set; }
	[Required]
	[ForeignKey("RoleId")]
	public virtual webpages_Roles webpages_Roles { get; set; }
	// Foreign keys to this table from other tables

}

The generator code examines the column definitions in Sql Server and uses the information to create the POCO object. It will check for non-null and add [Required] attributes, it will add [DefaultValue] attributes where a default is defined for the column and will emit [MaxLength] attributes for columns with a length, specifically varchar columns. It will also check for identity columns and it will add the “[Table]” attribute to the start of the class declaration to ensure EF gets the table name correct. (EF sometimes wants to pluralize table names. Maybe it’s just me.) I used the conversion table on MSDN’s SQL Server Data Type Mappings page to generate the right C# type for each column. One caveat though – I haven’t tested everything, and “user defined types” such as Geometry and Geography are all mapped as byte arrays.

There is one weakness that I have yet to be able to overcome, and that is handling cascading delete scenarios. SQL Server will automatically try to detect repeating cycles of cascades and will flag errors. Sometimes, such as the case above for “webpages_UsersInRoles” where there are multiple foreign keys, SQL Server can flag these even though the cascade won’t happen. You’ll need to use the Fluent API, with “.WillCascadeOnDelete(false)” to avoid this error. See this article for a better explanation.

There is one custom item in the generated attributes that are applied to the object properties, that is the “NoSpecialCharacters” attribute. This attribute is a one-liner that scans incoming character fields for symbols typically used in JavaScript and HTML and rejects the field if any of these are found. The definition is quite simple:

    public static class StringHelpers
    {
        /// <summary>
        /// Test for special characters in input data
        /// </summary>
        /// <param name="value"></param>
        /// <returns>false if there are special characters</returns>
        public static bool NoSpecialCharacters(this String value)
        {
            return (-1 == value.IndexOfAny(";<>\"[]&".ToCharArray()));
        }
    }

It’s not perfectly bulletproof, but it does go a long way towards preventing injection type attacks.

Accessing data through the created classes is pretty straightforward and there is a lot of information out there about how to do this. There is one thing that I would like to point out, that is that the [Required] attribute on the child foreign key relationships require accessing objects for editing and saving data in a particular manner.

    // accessing data for editing
    List<webpages_UsersInRoles> usersinroles = db.UserProfile
        .Where(p=>p.UserName==HttpContext.User.Identity.Name)
        .FirstOrDefault()
        .webpages_UsersInRoles.ToList();

    // Saving a new item
    db.UserProfile.Where(p=>p.UserName==HttpContext.User.Identity.Name)
        .webpages_UsersInRoles.Add(new_userinrole);

In the case of accessing data, the child items have to be accessed through the parent object. This sets up the foreign key relationship correctly; the same is true of saving a new object. While the child object can be created individually, it needs to be saved in relation to the correct parent object.

Read Full Post »

Well, hello there. It’s been a long (long!) time since I posted anything here. Since we’re well overdue for new content, I thought I’d post something quick and useful.

Any programmer who’s tried to write SQL queries is well aware that SQL does it’s own, limited, pattern matching for values in strings. As useful and powerful as SQL can be, it really needs better facilities for managing strings. In Microsoft SQL Server, that need can be answered through the use of a CLR function. That is, user written C# or VB (or any other CLR supported language) functions that can be called from your SQL statement to manipulate strings, implement complex business logic, or pretty much anything else. In this case, we’re going to add regular expression handling to SQL Server.

This journey began with the need to extract a business license number from a comment field. Unfortunately, the comment field held all sorts of information, such as who authorized the license, dates of one sort or another, phone numbers, and an unexpected multitude of ways to abbreviate “business license”. Not the sort of thing that native SQL could do – but could easily be handled through regular expression pattern matching. Unfortunately, SQL Server doesn’t support regular expressions. But – we can fix that!

There is a lot of information about writing CLR functions for SQL Server and much of it revolves around implementing regular expressions. This site is one of the best. However, the assembly presented there is in VB and I’m a C# guy. Their implementation also changes the order of parameters from the .NET Regular Expression object’s order, and I wanted to preserve the parameter order so that general reference material on .NET regular expressions would still be relevant – i.e. no hidden gotchas.

So, we’re off to writing our own CLR function for SQL. This turned out to be far simpler than expected, however I did run into one hiccup. The CLR function you create must be compiled for .NET 3.5 for SQL Server 2008. SQL Server 2012 will, I believe support .NET 4.0 and later. Several of the CLR regular expression implementations that you can find on the web include a step for creating a Regex object. My initial thoughts went along the lines of creating and then caching a Regex object in a static variable, and recreating the object whenever the search pattern changed. Ultimately, in the name of simplicity, I ended up using the Regex static methods and skipped manually creating any objects. Here’s my code for the Regex implementation:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using System.Data.Sql;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Collections;

namespace SQLRegularExpression
{
    public static class RegExFunctions
    {

        [SqlFunction(IsDeterministic=true, IsPrecise=true)]
        public static SqlInt32 RegExOptions(SqlBoolean IgnoreCase, SqlBoolean Multiline, SqlBoolean ExplicitCapture, SqlBoolean Compiled,
            SqlBoolean Singleline, SqlBoolean IgnorePatternWhitespace, SqlBoolean RightToLeft, SqlBoolean ECMAScript, SqlBoolean CultureInvariant)
        {
            RegexOptions options;

            options = (IgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None)
                | (Multiline ? RegexOptions.Multiline : RegexOptions.None)
                | (ExplicitCapture ? RegexOptions.ExplicitCapture : RegexOptions.None)
                | (Compiled ? RegexOptions.Compiled : RegexOptions.None)
                | (Singleline ? RegexOptions.Singleline : RegexOptions.None)
                | (IgnorePatternWhitespace ? RegexOptions.IgnorePatternWhitespace : RegexOptions.None)
                | (RightToLeft ? RegexOptions.RightToLeft : RegexOptions.None)
                | (ECMAScript ? RegexOptions.ECMAScript : RegexOptions.None)
                | (CultureInvariant ? RegexOptions.CultureInvariant : RegexOptions.None);

            return (Int32) options;
        }

        [SqlFunction(IsDeterministic=true, IsPrecise=true)]
        public static SqlString RegExMatch(SqlString input, SqlString pattern, SqlInt32 options)
        {
            if (input.IsNull || pattern.IsNull) return null;
            return Regex.Match(input.Value, pattern.Value, (RegexOptions)options.Value).Value;
        }

        [SqlFunction(IsDeterministic=true, IsPrecise=true)]
        public static SqlInt32 RegExIndex(SqlString input, SqlString pattern, SqlInt32 options)
        {
            if (input.IsNull || pattern.IsNull) return 0;
            return Regex.Match(input.Value, pattern.Value, (RegexOptions)options.Value).Index;
        }

        [SqlFunction(IsDeterministic=true, IsPrecise=true)]
        public static SqlBoolean RegExIsMatch(SqlString input, SqlString pattern, SqlInt32 options)
        {
            if (input.IsNull || pattern.IsNull) return false;
            return Regex.IsMatch(input.Value, pattern.Value, (RegexOptions)options.Value);
        }

        [SqlFunction(IsDeterministic = true, IsPrecise = true)]
        public static SqlString RegExReplace(SqlString input, SqlString pattern, SqlString replacement, SqlInt32 options)
        {
            if (input.IsNull || pattern.IsNull) return null;
            return Regex.Replace(input.Value, pattern.Value, replacement.Value, (RegexOptions)options.Value);
        }

        [SqlFunction(IsDeterministic = true, IsPrecise = true)]
        public static SqlString RegExSqlReplace(SqlString input, SqlString pattern, SqlString replacement)
        {
            if (input.IsNull || pattern.IsNull) return null;
            return Regex.Replace(input.Value, pattern.Value, replacement.Value, RegexOptions.IgnoreCase | RegexOptions.Multiline);
        }

        [SqlFunction(IsDeterministic=true, IsPrecise=true)]
        public static SqlString RegExEscape(SqlString input)
        {
            if (input.IsNull) return null;
            return Regex.Escape(input.Value);
        }

        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, IsPrecise = true, Name = "RegExSplit",
            SystemDataAccess = SystemDataAccessKind.None, FillRowMethodName = "RegExSplitRow")]
        public static IEnumerable RegExSplit(SqlString input, SqlString pattern, SqlInt32 options)
        {
            if (input.IsNull || pattern.IsNull) return null;
            return Regex.Split(input.Value, pattern.Value, (RegexOptions)options.Value);
        }

        public static void RegExSplitRow(Object input, ref SqlString match)
        {
            match = new SqlString(input.ToString());
        }

        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, IsPrecise = true, Name = "RegExMatches",
            SystemDataAccess = SystemDataAccessKind.None, FillRowMethodName = "RegExMatchesRow")]
        public static IEnumerable RegExMatches(SqlString input, SqlString pattern, SqlInt32 options)
        {
            if (input.IsNull || pattern.IsNull) return null;
            return Regex.Matches(input.Value, pattern.Value, (RegexOptions)options.Value);
        }

        public static void RegExMatchesRow(Object input, ref SqlString match, ref SqlInt32 matchIndex, ref SqlInt32 matchLength)
        {
            Match m = (Match)input;
            match = new SqlString(m.Value);
            matchIndex = m.Index;
            matchLength = m.Length;
        }
    }
}

That’s it. So what’s going on here that makes this class callable from SQL server? Well, there are a couple of things. First and foremost is the attribute declaring that each of the main interface functions is a ‘SQLFunction‘. The properties of the SQLFunction attribute class help define to SQL Server how and what the method it’s applied to interfaces with SQL Server. While we’re not going to talk about this in detail, a little later we will examine the “FillRowMethodName” property. The other point to mention is the use of the SqlXxxx variable types both for paramters and return values. These types contain extra information for dealing with Null values from SQL Server. Compile this with an output type of ‘Class Library’ and then copy the .dll file onto your SQL server machine.

On the SQL Server side, we need to register our new assembly and define the methods as functions. This script locates the .dll file you just copied to the SQL Server machine and declares each function. You will need to put in the path to the location of the .dll in the ‘Create Assembly’ statement in the middle of the script.

sp_configure 'clr enabled', 1
RECONFIGURE WITH OVERRIDE
 
-- ************************************************************************************************
-- Remove Function Entry Points
-- ************************************************************************************************
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExOptions') )
   DROP FUNCTION dbo.RegExOptions
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExSplit') )
   DROP FUNCTION dbo.RegExSplit
go
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExEscape') )
   DROP FUNCTION dbo.RegExEscape
go
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExReplace') )
   DROP FUNCTION dbo.RegExReplace
go
-- IF EXISTS ( SELECT   1
--             FROM     sys.objects
--             WHERE    object_id = OBJECT_ID(N'dbo.RegExReplacex') )
--    DROP FUNCTION dbo.RegExReplacex
-- go
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExIndex') )
   DROP FUNCTION dbo.RegExIndex
go
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExIsMatch') )
   DROP FUNCTION dbo.RegExIsMatch
go
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExMatch') )
   DROP FUNCTION dbo.RegExMatch
go
 
IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExMatches') )
   DROP FUNCTION dbo.RegExMatches
go
 
-- ************************************************************************************************
-- Remove the assembly from SQL Server
-- ************************************************************************************************

IF EXISTS ( SELECT   1
            FROM     sys.assemblies asms
            WHERE    asms.name = N'RegexFunction ' ) 
   DROP ASSEMBLY [RegexFunction]

-- ************************************************************************************************
-- Create Assembly reference
-- ************************************************************************************************

CREATE ASSEMBLY RegexFunction 
    FROM 'C:\\path\\to\\your\\assembly\\SQLRegularExpression.dll'
GO

-- ************************************************************************************************
-- Create Function Entry Points
-- ************************************************************************************************
 
CREATE FUNCTION [dbo].[RegExOptions]
      (
      @IgnoreCase bit,
        @MultiLine bit,
        @ExplicitCapture bit,
        @Compiled  bit,
        @SingleLine  bit,
        @IgnorePatternWhitespace  bit,
        @RightToLeft  bit,
        @ECMAScript  bit,
        @CultureInvariant  bit
        )
returns int
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExOptions
 
go
 
CREATE FUNCTION [dbo].[RegExIsMatch]
   (
    @Input NVARCHAR(MAX),
    @Pattern NVARCHAR(4000),
    @Options int
   )
RETURNS BIT
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExIsMatch
GO
 
CREATE FUNCTION [dbo].[RegExIndex]
   (
    @Input NVARCHAR(MAX),
    @Pattern NVARCHAR(4000),
    @Options int
   )
RETURNS int
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExIndex
GO
 
CREATE FUNCTION [dbo].[RegExMatch]
   (
    @Input NVARCHAR(MAX),
    @Pattern NVARCHAR(4000),
    @Options int
 )
RETURNS NVARCHAR(MAX)
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExMatch
GO
 
CREATE FUNCTION [dbo].[RegExEscape]
   (
    @Input NVARCHAR(MAX)
   )
RETURNS NVARCHAR(MAX)
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExEscape
GO

CREATE FUNCTION [dbo].[RegExSplit]
   (
    @Input NVARCHAR(MAX),
    @Pattern NVARCHAR(4000),
    @Options int
   )
RETURNS TABLE (Match NVARCHAR(MAX))
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExSplit
GO
 
CREATE FUNCTION [dbo].[RegExReplace]
   (
    @Input NVARCHAR(MAX),
    @Pattern NVARCHAR(4000),
    @Repacement NVARCHAR(MAX),
    @Options int
   )
RETURNS  NVARCHAR(MAX)
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExReplace
GO
 
CREATE FUNCTION [dbo].[RegExMatches]
   (
    @Input NVARCHAR(MAX),
    @Pattern NVARCHAR(4000),
    @Options int
   )
RETURNS TABLE (Match NVARCHAR(MAX), MatchIndex INT, MatchLength INT)
AS EXTERNAL NAME
   RegexFunction.[SQLRegularExpression.RegExFunctions].RegExMatches
GO

The one thing that astonished me about all this was that it worked the first time. That never happens! Anyway, there is one thing about these that I would like to point out: the two functions that return tables instead of a value. These are RegExSplit and RegExMatches. If you scroll up and look at the C# definitions, you will see a couple of things. First, these two functions return an IEnumerable instead of a value, and that each have the SQLFunction attribute parameter “FillRowMethodName” set to a function also defined in the C# code. What happens with these is that the base function does it’s thing and returns a list (IEnumerable) of results. The SQL interface process then calls the method defined in the “FillRowMethodName” property for each result entry in the IEnumerable. The first paramter to the fill row method is the enumerated object returned by the base call (RegExSplit or RegExMatches), and the second and later parameters are all defined as ‘ref’ parameters. You’ll notice that the SQL declaration for these functions returns a table whose columns exactly match those ‘ref’ parameters on the fill row method. So, each row of the result table is the product of calling the fill row method for each entry in the IEnumerable list returned by the base method.

So, how to use this? You can use the declared functions in the same way that you would use any other SQL Function. In this case, I’m using the RegExMatch function to extract the aforementioned business license number from the comments field, and using the RegExReplace function to remove terminal abbreviations for Street or Road (‘ST’ or ‘RD’, etc.) from the street name.

select 
    dbo.RegExMatch(comments, '\d{7}|d{6}', 0) as license, 
    street_number, 
    dbo.RegExReplace(street_name, '\bLN\Z|\bAV\Z|\bDR\Z|\bPL\Z|\bRD\Z|\bCR\Z|\bCT\Z|\bBL\Z|\bST\Z|\bWY\Z|\bHY\Z', '', 0) as name,
    city,
    state,
    zip
from mytable z

A final word on the use of CLR functions. Depending on your security setup, the use of external functions can be considered a security risk. You will need to evaluate the business need for functions like this against the risks involved. You should also be wary of using CLR functions in SQL Server to implement functionality that architecturally belongs in the business or presentation layers. This I would strongly encourage you to not do. Put things where they belong, even if it’s difficult, and you’ll be rewarded with a better performing, more maintainable system overall.

Read Full Post »

This is the sixth and final entry in a series on the development of support for stored procedures in a Code First style. See Code First Stored Procedures for the final product.

Don’t make promises you won’t keep. 🙂

Last time, I promised that it was the final post on the Code First Stored Procedures development process. I lied. So sue me. The problem is that I absolutely hated the handling of table valued parameters, and how the table definition had to be created in user code. Very not “Code First” style. So, I finally found the time to go back and redo that portion of the code.

What I wanted to do was to decorate a class with the table definition rather than making a separate table definition in code – basically, create the table definition using the same style and attributes that we use for managing the stored procedure input and output parameters. The key to doing this is dynamically creating the table definition based on attributes in the code that turns the list of objects into the table for the table valued parameter.

The result is that the TableType class is completely gone. Table definitions are now created by decorating a class with the schema and table name, and decorating the methods with the column definitions. For example, if we have a table definition and stored procedure definition like this:

-- Create Table variable 
create type [dbo].[testTVP] AS TABLE(
 [testowner] [nvarchar] (50) not null, 
 [testtable] [nvarchar] (50) NULL,
 [testcolumn] [nvarchar](50) NULL
)
GO

-- Create procedure using table variable
create proc testfour @tt testTVP readonly
as
begin
	select table_schema, table_name, column_name from INFORMATION_SCHEMA.COLUMNS
	inner join @tt
	on table_schema = testowner
	where (testtable is null or testtable = table_name)
	and (testcolumn is null or testcolumn = column_name)
end
go

The class that matches the ‘testTVP’ table type would look like this:

    /// <summary>
    /// Class representing a row of data for a table valued parameter.  
    /// Property names (or Name attribute) must match table type column names
    /// </summary>
    [StoredProcAttributes.Schema("dbo")]
    [StoredProcAttributes.TableName("testTVP")]
    public class sample
    {
        [StoredProcAttributes.Name("testowner")]
        [StoredProcAttributes.ParameterType(SqlDbType.VarChar)]
        [StoredProcAttributes.Size(50)]
        public string owner { get; set; }

        [StoredProcAttributes.ParameterType(SqlDbType.VarChar)]
        [StoredProcAttributes.Size(50)]
        public string testtable { get; set; }

        [StoredProcAttributes.ParameterType(SqlDbType.VarChar)]
        [StoredProcAttributes.Size(50)]
        public string testcolumn { get; set; }
    }

The table name and schema attributes on the class define the SQL object that will match this definition, and the parametertype and size attributes define the matching SQL column definitions. This will be dynamically assembled into the messy column definition structure that I used to store in the old TableType class. Since this is now dynamically generated, we can drop the TableType class like a hot rock.

Using a table valued parameter now becomes much cleaner. The class for the stored procedure input parameters for the above example is now dead simple. The parametertype attribute of ‘Structured’ identifies that method as a table valued parameter and to expect a list of objects that contain the needed attributes to create the table definition.

    /// <summary>
    /// Parameter object for 'testfour' stored procedure
    /// </summary>
    [StoredProcAttributes.Name("testfour")]
    public class testfourdata
    {
        [StoredProcAttributes.ParameterType(SqlDbType.Structured)]
        [StoredProcAttributes.Name("tt")]
        public List<sample> tabledata { get; set; }
    }

The call to use the table valued parameter remains pretty much what it was, with the removal of the extra layer of assignments required by the (now removed) TableType parameter:

                //-------------------------------------------------------------
                // Stored proc with a table valued parameter
                //-------------------------------------------------------------
                
                // new parameters object for testfour
                testfourdata four = new testfourdata();
                
                // load data to send in the table valued parameter 
                four.tabledata = new List()
                {
                    new sample() { owner = "tester" },
                    new sample() { owner = "dbo" }
                };

                // call stored proc
                var ret4 = te.CallStoredProc(te.testfourproc, four);
                var retdata = ret4.ToList();

And there you have it – a Code First style of POCO classes and attributes to define properties and behaviors needed to support stored procedure calls.

Read Full Post »

This is the fifth entry in a series on the development of support for stored procedures in a Code First style. See Code First Stored Procedures for the final product.

Ok, this is the last one. I promise. For a while at least.

I’ve finally completed the CodeFirstStoredProc module, and in the process completely changed the way the interface works. The “ParameterHolder” class is gone, completely. In it’s place, the parameters for a stored proc are taken from a class, and attributes are used to define the SqlParameter properties for that particular parameter. This has resulted in simplifying the interface somewhat, though much of the previous version remains. The TableType and StoredProc classes remain essentially the same, but how they are used has changed a bit. Here’s an example of a parameters class:

    /// <summary>
    /// Parameters object for the 'testoneproc' stored procedure
    /// </summary>
    public class testone
    {
        // Override the parameter name. The parameter name is "in", but that's not a valid property
        // name in C#, so we must name the property something else and provide an override to set 
        // the parameter name.
        [StoredProcAttributes.Name("in")]
        [StoredProcAttributes.ParameterType(System.Data.SqlDbType.VarChar)]
        public String inparm { get; set; }

        // This time we not only override the parameter name, we're also setting the parameter
        // direction, indicating that this property will only recieve data, not provide data
        // to the stored procedure. Note that we include the size in bytes.
        [StoredProcAttributes.Name("out")]
        [StoredProcAttributes.Direction(System.Data.ParameterDirection.Output)]
        [StoredProcAttributes.Size(4)]
        public Int32 outparm { get; set; }
    }

The attributes belonging to the namespace “StoredProcAttributes” tell the process how to create the SqlParameters. This is a much cleaner interface, and achieves the goal of separating definition from use. Making a call to the stored procedure is now a bit simpler. You create an instance of the parameters class, and use it to call the stored procedure.

            using (testentities te = new testentities())
            {
                //-------------------------------------------------------------
                // Simple stored proc
                //-------------------------------------------------------------
                StoredProc<testone> testoneproc =
                    new StoredProc<testone>(typeof(TestOneResultSet));
                var parms1 = new testone() { inparm = "abcd" };
                var results1 = te.CallStoredProc<testone>(testoneproc, parms1);
                var r1 = results1.ToList<TestOneResultSet>();
            }

Creating and using TableValued Parameters is now a bit simpler as well. Separating definition from use, once again, helps keep the implemetation code clean and increases code re-use. To make a call to a stored procedure that accepts a table-valued parameter, we first create the tvp definition as a property in a parameters class.

    /// <summary>
    /// Parameter object for 'testfour' stored procedure
    /// </summary>
    public class testfour
    {
        // Table valued parameter - pass in a list (table) of data to the stored procedure
        public TableType<sample> tt { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public testfour()
        {
            // Define our TableValuedParameter. 'schema' and 'tablename' identify the 
            // user defined table type of the parameter, 'sourcetype' identifies the 
            // .Net object used to pass individual rows of data and 'columns' contains
            // the definition of the table type. In 'columns', the number is used to 
            // sort the columns in proper order, and the SqlMetaData value defines the
            // individual column
            tt = new TableType<sample>()
            {
                schema = "dbo",
                tablename = "testTVP",
                columns = new List<Microsoft.SqlServer.Server.SqlMetaData>()
                {
                    {new Microsoft.SqlServer.Server.SqlMetaData("testowner", SqlDbType.VarChar, 50)},
                    {new Microsoft.SqlServer.Server.SqlMetaData("testtable", SqlDbType.VarChar, 50)},
                    {new Microsoft.SqlServer.Server.SqlMetaData("testcolumn", SqlDbType.VarChar, 50)}
                }
            };
        }
    }

Once the parameter class is defined,using it to make a stored procedure call follows the same pattern as other stored procedure calls: create an instance of the paramters class, fill in the values and make the stored procedure call.

            using (testentities te = new testentities())
            {
                //-------------------------------------------------------------
                // Stored proc with a table valued parameter
                //-------------------------------------------------------------
                
                // new parameters object for testfour
                testfour four = new testfour();
                
                // load data to send in the table valued parameter 
                four.tt.sourcedata = new List<sample>()
                {
                    new sample() { owner = "tester" },
                    new sample() { owner = "dbo" }
                };

                // call stored proc
                var ret4 = te.CallStoredProc<testfour>(te.testfour, four);
                var retdata = ret4.ToList<TestFourResultSet>();
            }

Now, isn’t that much better than before?

Read Full Post »

This is the fourth in a series on the development of support for stored procedures in a Code First style. See Code First Stored Procedures for the final product.

Boy, I just can’t seem to let this one rest. I do, however, have an overall improvement on things so far. First, I’m introducing two new objects. The first is StoredProc and the second is TableType. These both remove the “declaration” of stored procedures and user table types from the implementation code and give them their own, reusable definitions. Overall, this should both increase the reusability and object-orientedness of the code and make things easier to understand.

The two objects are very similar. Each contains parameters for the schema and name of the object, and a list of data elements. For the StoredProc type, this is the list of types being returned, and for the TableType this list is the column definitions in SqlMetaData objects.

    /// <summary>
    /// Represents a Stored Procedure in the database
    /// </summary>
    public class StoredProc
    {
        /// <summary>
        /// List of data types that this stored procedure returns as result sets. 
        /// Order is important!
        /// </summary>
        internal List<Type> outputtypes = new List<Type>();

        /// <summary>
        /// Database owner of this object
        /// </summary>
        public String schema { get; set; }

        /// <summary>
        /// Name of the stored procedure
        /// </summary>
        public String procname { get; set; }

        /// <summary>
        /// Fluent API - assign owner (schema)
        /// </summary>
        /// <param name="owner"></param>
        /// <returns></returns>
        public StoredProc HasOwner(String owner)
        {
            schema = owner;
            return this;
        }

        /// <summary>
        /// Fluent API - assign procedure name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public StoredProc HasName(String name)
        {
            procname = name;
            return this;
        }

        /// <summary>
        /// Fluent API - set the data types of resultsets returned by the stored procedure. 
        /// Order is important!
        /// </summary>
        /// <param name="types"></param>
        /// <returns></returns>
        public StoredProc ReturnsTypes(params Type[] types)
        {
            outputtypes.AddRange(types);
            return this;
        }

        /// <summary>
        /// Get an array of types returned
        /// </summary>
        public Type[] returntypes
        {
            get { return outputtypes.ToArray(); } 
        }

        /// <summary>
        /// Get the fully (schema plus owner) name of the stored procedure
        /// </summary>
        public String fullname
        {
            get { return schema + "." + procname; }
        }

        /// <summary>
        /// Constructors
        /// </summary>
        public StoredProc()
        {
            schema = "dbo";
        }

        public StoredProc(String name)
        {
            schema = "dbo";
            procname = name;
        }

        public StoredProc(String name, params Type[] types)
        {
            schema = "dbo";
            procname = name;
            outputtypes.AddRange(types);
        }

        public StoredProc(String owner, String name, params Type[] types)
        {
            schema = owner;
            procname = name;
            outputtypes.AddRange(types);
        }
    }

    public class TableType
    {
        /// <summary>
        /// Database object owner
        /// </summary>
        public String schema { get; set; }

        /// <summary>
        /// Database object name
        /// </summary>
        public String tablename { get; set; }

        /// <summary>
        /// Meta data definition of the underlying table object for the table valued parameter. Dictionary 
        /// contains the column order and the column definition.
        /// </summary>
        Dictionary<int, SqlMetaData> columns = new Dictionary<int, SqlMetaData>();

        /// <summary>
        /// Sort columns by given order and convert columns data to array
        /// </summary>
        /// <returns></returns>
        public SqlMetaData[] ToArray()
        {
            return columns.OrderBy(p => p.Key).Select(p => p.Value).ToArray();
        }

        /// <summary>
        /// Add a column definition
        /// </summary>
        /// <param name="column"></param>
        public TableType AddColumn(int colno, SqlMetaData column)
        {
            columns.Add(colno, column);
            return this;
        }

        /// <summary>
        /// Add a range of column definitions
        /// </summary>
        /// <param name="cols"></param>
        public TableType AddColumns(Dictionary<int, SqlMetaData> cols)
        {
            columns = (Dictionary<int, SqlMetaData>)columns.Concat(cols);
            return this;
        }

        /// <summary>
        /// Constructors
        /// </summary>
        public TableType()
        {
            schema = "dbo";
        }

        public TableType(String name)
        {
            schema = "dbo";
            tablename = name;
        }

        public TableType(String name, Dictionary<int, SqlMetaData> cols)
        {
            schema = "dbo";
            tablename = name;
            columns = cols;
        }

        public TableType(String owner, String name, Dictionary<int, SqlMetaData> cols)
        {
            schema = owner;
            tablename = name;
            columns = cols;
        }
    }

Nothing overly complicated, just multiple constructors and Fluent API interface styling. What these do, however is more fundamental. These objects allow you to create the StoredProc and TableType references away from your implementation code and in with the rest of your declarations. Personally, I like to add these to the DbContext object declaration where they will reside along with all the other database object definitions. This is not necessary, of course, and may not be desirable depending on your situation.

    public class testentities : DbContext
    {
        // basic procs
        public StoredProc testone { get; set; }
        public StoredProc testtwo { get; set; }
        public StoredProc testthree { get; set; }

        // table valued parameter proc
        public TableType testtable { get; set; }
        public StoredProc testfour { get; set; }

        // constructor
        public testentities()
            : base()
        {
            testone = new StoredProc("testone", typeof(TestOne));

            testtwo = new StoredProc()
                .HasName("testtwo")
                .ReturnsTypes(typeof(TestTwo));

            testthree = new StoredProc()
                .HasName("testthree")
                .ReturnsTypes(typeof(TestOne), typeof(TestTwo));

            testtable = new TableType()
                .AddColumn(1, new Microsoft.SqlServer.Server.SqlMetaData("testowner", SqlDbType.VarChar, 50))
                .AddColumn(2, new Microsoft.SqlServer.Server.SqlMetaData("testtable", SqlDbType.VarChar, 50))
                .AddColumn(4, new Microsoft.SqlServer.Server.SqlMetaData("testcolumn", SqlDbType.VarChar, 50));

            testfour = new StoredProc()
                .HasName("testfour")
                .ReturnsTypes(typeof(testfour));
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

Use of these has required modifications to the TableValuedParameter object, and a new “CallStoredProc” routine. The TableValuedParameter object now no longer contains the table definition, greatly simplifying it. It still contains the logic to build the output list of SqlDataRecords, bringing together the source data and the TableType definition.

    /// <summary>
    /// Hold data for a table-valued parameter, and convert according to given table definition
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class TableValuedParameter<T> 
    {
        /// <summary>
        /// pointer to our input data
        /// </summary>
        IEnumerable<T> data;

        /// <summary>
        /// type of table that we'll convert the source data into
        /// </summary>
        TableType basetable;

        /// <summary>
        /// Constructor, takes table definition and table source
        /// </summary>
        /// <param name="table"></param>
        /// <param name="source"></param>
        public TableValuedParameter(TableType table, IEnumerable<T> source)
        {
            data = source;
            basetable = table;
        }

        /// <summary>
        /// Do the work of converting the source data to the table type
        /// </summary>
        /// <returns></returns>
        public IEnumerable<SqlDataRecord> Value()
        {
            // list of converted values to be returned to the caller
            List<SqlDataRecord> recordlist = new List<SqlDataRecord>();

            // get all mapped properties
            PropertyInfo[] props = typeof(T).GetMappedProperties();

            // get the column definitions, in the right order, into an array
            var valuearray = basetable.ToArray();

            // load each object in the input data table into sql data records
            foreach (T s in data)
            {
                // create the sql data record using the column definition
                SqlDataRecord record = new SqlDataRecord(valuearray);
                for (int i = 0; i < valuearray.Count(); i++)
                {
                    // locate the value of the matching property
                    var value = props.Where(p => p.Name == valuearray[i].Name)
                        .First()
                        .GetValue(s, null);

                    // set the value
                    record.SetValue(i, value);
                }
                // add the sql data record to our output list
                recordlist.Add(record);
            }

            // return our list of data records
            return recordlist;
        }
    }

The new CallStoredProc routine is, like ReadFromStoredProc an extension method off of the DbContext object, and basically just wraps the ReadFromStoredProc routine. The ReadFromStoredProc routine may disappear in a future version.

To use these, little has changed besides the call to execute the stored procedure. Here is our previous TableValuedParameter example, using the new interface.

                // first create some data for our table
                List<sample> sampledata = new List<sample>();
                sampledata.Add(new sample() { testowner = "tester" });
                sampledata.Add(new sample() { testowner = "dbo" });

                TableValuedParameter<sample> TVP = new TableValuedParameter<sample>(te.testtable, sampledata);

                // add the table valued parameter to a parameterlist
                ParameterList parametersTVP = new ParameterList();
                parametersTVP.Add(new SqlParameterHolder()
                {
                    Name = "tt",
                    Value = TVP.Value(),
                    ParameterType = SqlDbType.Structured,
                    TypeName = "sample"                    
                });

                // call our stored procedure
                var resultset4 = te.CallStoredProc(te.testfour, parametersTVP);
                List<testfour> testfour4 = resultset4.ToList<testfour>();

And there we are. Better code/object reuse, simpler calls and better separation of declaration and implementation code.

Read Full Post »

This is the third in a series on the development of support for stored procedures in a Code First style. See Code First Stored Procedures for the final product.

This post builds on the previous post: “CodeFirst and Stored Procedures 2“. In that post I presented an implementation for handling calls to Stored Procedures for CodeFirst. However, there is one possibility not covered by that post: using Table Valued Parameters.

First, to explain what Table Valued Parameters are. Basically, it is what it’s name implies: passing a table to a stored procedure as an input parameter. What’s nice about this is that you can treat the input data as a table in the stored procedure, using it in joins, subqueries, etc. It is the easiest way to pass multiple data values into a stored proc and it greatly simplifies the SQL in the stored procedure. To get the same function without Table Valued Paremeters, you would need to create XML in your code, pass it as a string to the stored procedure, and then process it as XML in the stored proc. A messy business under the best of conditions.

To use Table Valued Parameters, you first need a table. T-SQL allows you to create a table type which you can then use as a parameter. To create the table type you will need to do something like:

-- Create Table variable 
create type [dbo].[testTVP] AS TABLE(
    [testowner] [nvarchar] (50) not null, 
    [testtable] [nvarchar] (50) NULL,
    [testcolumn] [nvarchar](50) NULL
)
GO

In this example, we see the creation of a user type as a table. This type can be declared as a variable or a parameter in a stored procedure and used in the same way any other table could be used. For example:

-- Create procedure using table variable
create proc testfour @tt testTVP readonly
as
begin
	select table_schema, table_name, column_name from INFORMATION_SCHEMA.COLUMNS
	inner join @tt
	on table_schema = testowner
	where (testtable is null or testtable = table_name)
	and (testcolumn is null or testcolumn = column_name)
end
go

Here we see a parameter being defined as our table type, and then being used in the SQL as a participant in the join. The “readonly” modifier for the parameter is required. A table passed in as a parameter cannot be modified within the body of the stored procedure.

To use this stored procedure in T-SQL you would do something like:

declare @p1 dbo.testTVP
insert into @p1 values('tester',NULL,NULL)

exec dbo.testfour @tt=@p1

So, how to do this in code?

The two classes we need to use to deal with this are the SQLMetaData class to define the columns for our table type, and SQLDataRecord to hold rows for our table type. To bring both of these together and to allow the use of a POCO object for the source data (keep things simple!) we have the TableValuedParameter object.

    /// <summary>
    /// Hold definition and data for a table-valued parameter. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class TableValuedParameter<T> 
    {

        /// <summary>
        /// pointer to our input data
        /// </summary>
        IEnumerable<T> data;

        /// <summary>
        /// Meta data definition of the underlying table object for the table valued parameter. Dictionary 
        /// contains the column order and the column definition.
        /// </summary>
        Dictionary<int, SqlMetaData> columns = new Dictionary<int, SqlMetaData>();

        /// <summary>
        /// Constructor, takes the data source and optionally, the column definitions
        /// </summary>
        /// <param name="source"></param>
        /// <param name="cols"></param>
        public TableValuedParameter(IEnumerable<T> source, Dictionary<int, SqlMetaData> cols = null)
        {
            data = source;
            if (null != cols)
                columns = cols;
        }

        /// <summary>
        /// Add a column definition
        /// </summary>
        /// <param name="column"></param>
        public void AddColumn(int colno, SqlMetaData column)
        {
            columns.Add(colno, column);
        }

        /// <summary>
        /// Add a range of column definitions
        /// </summary>
        /// <param name="cols"></param>
        public void AddColumns(Dictionary<int, SqlMetaData> cols)
        {
            columns = (Dictionary<int, SqlMetaData>)columns.Concat(cols);
        }

        /// <summary>
        /// Process the input data into SQL data records using the provided
        /// column definitions. Data properties are extracted by matching the 
        /// property name with the name of the column
        /// </summary>
        /// <returns></returns>
        public IEnumerable<SqlDataRecord> Value()
        {
            // list of converted values to be returned to the caller
            List<SqlDataRecord> recordlist = new List<SqlDataRecord>();

            // get all mapped properties
            PropertyInfo[] props = typeof(T).GetMappedProperties();

            // get the column definitions, in the right order, into an array
            var valuearray = columns.OrderBy(p => p.Key).Select(p => p.Value).ToArray();

            // load each object in the input data table into sql data records
            foreach (T s in data)
            {
                // create the sql data record using the column definition
                SqlDataRecord record = new SqlDataRecord(valuearray);
                for (int i = 0; i < valuearray.Count(); i++)
                {
                    // locate the value of the matching property
                    var value = props.Where(p => p.Name == valuearray[i].Name)
                        .First()
                        .GetValue(s, null);

                    // set the value
                    record.SetValue(i, value);
                }
                // add the sql data record to our output list
                recordlist.Add(record);
            }
 
            // return our list of data records
            return recordlist;
        }
    }

This object takes an IEnumerable as a data source and a set of column definitions as it’s constructor. Alternately, the column definitions can be provided separately, and in any order. What’s important is that the order number used in adding the column definitions is the same order as the source table definition. The major work of this object is in the Value() method. This method creates a list of SqlDataRecords using the column definitions, and then populates that data record by matching the column name with the property name in the data source.

When the Table Valued Parameter is passed to the stored procedure, we need to indicate that this is a “Structured” type and provide the name of the table type in the database. The DbParameter (and consequently, our DbParameterHolder) does not have these fields available. To handle this we create a new type, SqlParameterHolder, that inherits from DbParameterHolder, and contains the necessary extra values.

    /// <summary>
    /// Define a parameter for a Stored Procedure call. This inherits from DbParameterHolder and adds
    /// properties that are needed for a SQL parameter 
    /// </summary>
    public class SqlParameterHolder : DbParameterHolder
    {
        /// <summary>
        /// override for the SQL version of the parameter
        /// </summary>
        public new SqlDbType ParameterType { get; set; }

        /// <summary>
        /// Type name for table valued parameters
        /// </summary>
        public String TypeName { get; set; }

        /// <summary>
        /// Copy parameter data from our ParameterHolder carrier object to database parameter objects
        /// </summary>
        /// <param name="cmd">Command object created from the connection</param>
        /// <returns>SqlParameter object cast as DbParameter</returns>
        public override DbParameter toParameter(DbCommand cmd)
        {
            SqlParameter param = (SqlParameter)cmd.CreateParameter();
            param.ParameterName = Name;
            param.Value = Value ?? DBNull.Value;
            param.SqlDbType = ParameterType;
            param.TypeName = TypeName;
            param.Direction = Direction;
            param.Size = Size;
            return (DbParameter) param;
        }
    }

Each object, DbParameterHolder and SqlParameterHolder, has a ToParameter method added that converts the parameter holder data into the corresponding parameter type. The ToParameter methods are declared such that the inherited SqlParameter’s method overrides the base classes’s ToParameter method, allowing us to simply call the method and having the object typing ensure that the correct object’s method is called automatically.

Now, to put it all together. To use this we will create a Table Valued Parameter object and pass it to our ReadFromStoredProcedure just like any other parameter. Like any other CodeFirst interaction, we need some POCO objects to store our input and output data.

    /// <summary>
    /// input class for table valued parameter.  Property names must match table type column names
    /// </summary>
    public class testTVP
    {
        public string testowner { get; set; }
        public string testtable { get; set; }
        public string testcolumn { get; set; }
    }

    /// <summary>
    /// output class for proc test four
    /// </summary>
    public class testfour
    {
        public string table_schema { get; set; }
        public string table_name { get; set; }
        public string column_name { get; set; }
    }

Once we have our objects we can load some data, and call our stored procedure.

                // first create some data for our table
                List<testTVP> tvpdata = new List<testTVP>();
                tvpdata.Add(new testTVP() { testowner = "tester" });
                tvpdata.Add(new testTVP() { testowner = "dbo" });

                // generate the table valued parameter and add columns
                TableValuedParameter<testTVP> TVP = new TableValuedParameter<testTVP>(tvpdata);
                TVP.AddColumn(1, new Microsoft.SqlServer.Server.SqlMetaData("testowner", SqlDbType.VarChar, 50));
                TVP.AddColumn(2, new Microsoft.SqlServer.Server.SqlMetaData("testtable", SqlDbType.VarChar, 50));
                TVP.AddColumn(3, new Microsoft.SqlServer.Server.SqlMetaData("testcolumn", SqlDbType.VarChar, 50));

                // add the table valued parameter to a parameterlist
                ParameterList parametersTVP = new ParameterList();
                parametersTVP.Add(new SqlParameterHolder()
                {
                    Name = "tt",
                    Value = TVP.Value(),
                    ParameterType = SqlDbType.Structured,
                    TypeName = "testTVP"                    
                });

                // call our stored procedure
                var resultset4 = te.ReadFromStoredProc("dbo.testfour", parametersTVP, typeof(testfour));
                List<testfour> testfour4 = resultset4.ToList<testfour>();

This example is a bit more complex than those in my previous post, but we’re doing something much more complicated. First we need to create a list of multiple values to pass to our stored procedure. Then we create a Table Valued Parameter object and provide a table definition. Then we create the parameter list and parameter holder object. In this case, note that we’re not only providing the name of the parameter (“tt”), but also the name of the table type so that SQL knows what we’re doing. After all this, the call to the stored procedure seems a bit anticlimactic, but it’s the same type of call we’ve been using all along.

So, one might ask, “Why do you make me create a table definition? Why not just add a table definition to my DbContext object?”. Two reasons for this, both having to do with the fact that the table type is not an actual table. First, if you were to create a table definition in your DbContext object and then regenerate your database, the generation would fail. Secondly, I don’t want to give the mistaken impression that the table type was an available table that you could query and add or remove data from. A possible future enhancement might be to find a way to add the table type definition to the DbContext object in such a way that it is clear that this is a table type and not a table.

Read Full Post »

This is the second in a series on the development of support for stored procedures in a Code First style. See Code First Stored Procedures for the final product.

My previous post on CodeFirst and Stored Procedures introduced a rather basic method for passing in parameters to a stored procedure and retrieving a single table as a result set. This was useful, but often stored procedures return data in their parameters, or via a return code. Many stored procedures also return multiple result sets. So, what to do??

Well, first things first. How to get data back out of parameters? The call to execute the stored procedure does this automatically – however, it only updates the DbParameter class objects inside the command object, not our parameter data carrier object. So, what we need is a flag indicating that a parameter is expecting returned data, and then to process them after the stored procedure returns. The ParmInfo class gets renamed ParameterHolder and expanded to include a couple of new properties:

    /// <summary>
    /// Define a parameter for a Stored Procedure call.
    /// </summary>
    public class ParameterHolder
    {
        /// <summary>
        /// Name of the parameter. This is the name of the parameter in the Stored Procedure definition.
        /// </summary>
        public String Name { get; set; }

        /// <summary>
        /// Value of this parameter.
        /// </summary>
        public Object Value { get; set; }

        /// <summary>
        /// DataBase type of the parameter.
        /// </summary>
        public System.Data.DbType ParameterType { get; set; }

        /// <summary>
        /// Size of the value in bytes. This is most important for return values. The Size must be big enough 
        /// to accomodate the actual return value.
        /// </summary>
        public Int32 Size { get; set; }

        /// <summary>
        /// Flag indicating if this parameter is a database "null" value
        /// </summary>
        public Boolean isDbNull { get; set; } 

        /// <summary>
        /// Define the direction of data flow for this parameter. Anything other than 'Input' can recieve 
        /// a value set by the Stored Procedure. Defaults to 'Input'.
        /// </summary>
        public ParameterDirection Direction { get; set; }

        /// <summary>
        /// Default Constructor
        /// </summary>
        public ParameterHolder()
        {
            // set default values
            Direction = ParameterDirection.Input;
            isDbNull = false;
        }
    }

    /// <summary>
    /// List of parameters for a Stored Procedure call. Provides access routines to the returned 
    /// parameter values
    /// </summary>
    public class ParameterList : List<ParameterHolder>
    {
        /// <summary>
        /// Locate a ParameterHolder by its Name property
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        public ParameterHolder Get(String Name)
        {
            return this.Where(p => p.Name == Name)
                .FirstOrDefault();
        }

        /// <summary>
        /// Returns the Value of a named Parameter, cast to the appropriate type
        /// </summary>
        /// <typeparam name="T">Type to cast the Value to</typeparam>
        /// <param name="Name">Name of the parameter to find</param>
        /// <returns>Value of the named parameter, cast to the indicated type</returns>
        public T GetValue<T>(String Name)
        {
            ParameterHolder parm = Get(Name);
            if ((parm.isDbNull || typeof(System.DBNull) == parm.Value.GetType()))
                return default(T);
            else
                return (T)(parm.Value);
        }
    }

The unimplemented “outparm” is replaced by the ‘Direction’ attribute. The ‘Direction’ attribute is used to indicate whether a parameter is sending data in, out, or some combination in between. The ‘size’ parameter is used for output parameters, indicating the expected size of the data. If this is too small, your data will be truncated! I’ve also added a class for the list of parameters. This is a simple override of the List class, but it does provide a pair of useful routines for getting at output parameters.

Now that we have the extra properties in the ParameterHolder carrier object, we need to pass them on to the DbParameter. This was done in the ‘AddParameter’ method, which now becomes:

        /// <summary>
        /// Copy parameter data from our ParameterHolder carrier object to database parameter objects
        /// </summary>
        /// <param name="cmd">Command object created from the connection</param>
        /// <param name="p">ParameterHolder carrier object to be turned into a DbParameter</param>
        public static void AddParameter(this DbCommand cmd, ParameterHolder p)
        {
            DbParameter param = cmd.CreateParameter();
            param.ParameterName = p.Name;
            param.Value = p.Value ?? DBNull.Value;
            param.DbType = p.ParameterType;
            param.Direction = p.Direction;
            param.Size = p.Size;
            cmd.Parameters.Add(param);
        }

And, lastly, we need to modify the method that actually calls the stored procedure, adding the following lines of code after the ExecuteReader() call. This processes all of the ‘return value’ parameters, extracting any values set by the stored procedure call.

                    // Collect values for output parameters - everything except pure input can have a return value
                    if (null != parms)
                    {
                        foreach (ParameterHolder p in parms
                            .Where(p => p.Direction != ParameterDirection.Input)
                            .Select(p => p))
                        {
                            p.Value = cmd.Parameters[p.Name].Value;
                        }
                    }

That will handle output and return value parameters.

So, what about multiple result sets? The problem with multiple result sets is that we want to continue to stick with the CodeFirst paradigm of using lightweight, POCO objects for our data (i.e. no DataTables!), but at the same time we’ve got to handle a call that will potentially return multiple types. How do we tell the code that processes the stored procedure what to expect?

Here’s one solution to the problem. To handle multiple result sets we pass in a list of the types expected, and we get back a List of Lists containing our data. The new routine to call a stored procedure now looks like this:

        /// <summary>
        /// Call a stored procedure and get results back. This routine handles both output parameters
        /// and multiple result sets. The Type objects must have a default constructor!
        /// </summary>
        /// <param name="context">Code First database context object</param>
        /// <param name="procname">Qualified name of proc to call</param>
        /// <param name="parms">List of ParameterHolder objects - input and output parameters</param>
        /// <param name="outputtypes">List of types to expect in return. Each type *must* have a default constructor.</param>
        /// <returns></returns>
        public static ResultsList ReadFromStoredProc(this DbContext context,
            String procname,
            IEnumerable<ParameterHolder> parms = null,
            params Type[] outputtypes)
        {
            // create our output set object
            ResultsList results = new ResultsList();

            // ensure that we have a type list, even if it's empty
            IEnumerator currenttype = (null == outputtypes) ?
                new Type[0].GetEnumerator() :
                outputtypes.GetEnumerator();

            // handle to the database connection object
            var connection = context.Database.Connection;
            try
            {
                // open the connect for use and create a command object
                connection.Open();
                using (var cmd = connection.CreateCommand())
                {
                    // command to execute is our stored procedure
                    cmd.CommandText = procname;
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    // move parameters to command object
                    if (null != parms)
                        foreach (ParameterHolder p in parms)
                            cmd.AddParameter(p);

                    // Do It! This actually makes the database call
                    var reader = cmd.ExecuteReader();

                    // get the type we're expecting for the first result. If no types specified,
                    // ignore all results
                    if (currenttype.MoveNext())
                    {
                        // process results - repeat this loop for each result set returned by the stored proc
                        // for which we have a result type specified
                        do
                        {
                            // get properties to save for the current destination type
                            PropertyInfo[] props = ((Type)currenttype.Current).GetMappedProperties();

                            // create a destination for our results
                            List<object> current = new List<object>();

                            // process the result set
                            while (reader.Read())
                            {
                                // create an object to hold this result
                                object item = ((Type)currenttype.Current).GetConstructor(System.Type.EmptyTypes).Invoke(new object[0]);

                                // copy data elements by parameter name from result to destination object
                                reader.ReadRecord(item, props);

                                // add newly populated item to our output list
                                current.Add(item);
                            }

                            // add this result set to our return list
                            results.Add(current);
                        }
                        while (reader.NextResult() && currenttype.MoveNext());
                    }
                    // close up the reader, we're done saving results
                    reader.Close();

                    // Collect values for output parameters - everything except pure input can have a return value
                    if (null != parms)
                    {
                        foreach (ParameterHolder p in parms
                            .Where(p => p.Direction != ParameterDirection.Input)
                            .Select(p => p))
                        {
                            p.Value = cmd.Parameters[p.Name].Value;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error reading from stored proc " + procname + ": " + ex.Message, ex);
            }
            finally
            {
                connection.Close();
            }

            return results;
        }

This is structurally similar to the previous posts’ routine, but has several significant differences. First is that list of types as optional input parameters. This list tells the routine what types to expect as result sets from the stored procedure. If this is null, then an empty list is created and no result sets are read from the stored procedure.

So what’s happening down in side? All the interesting stuff happens after the call to the stored procedure. We’ve got a set of nested loops that process each result set if A) there is a result set to process and B) we’ve been given a type to process the data into. Within those loops we have a call to determine what are the mapped properties of the output Type – that is properties that do not have the “NotMapped” attribute applied, and a call to create an object to receive the data. First lets look at that constructor. The call is

// create an object to hold this result
object item = ((Type)currenttype.Current).GetConstructor(System.Type.EmptyTypes).Invoke(new object[0]);

This takes the current type in our list and calls the default constructor. Which brings up an important point. In order to use this routine, all the output types must have a default constructor, that is a constructor with no parameters. Given an object that we want to store data into, we have to be sensitive to the ‘NotMapped’ attribute. Properties with this attribute should not be read from the data. How to do this? The GetMappedProperties routine does this for us:

        /// <summary>
        /// Get properties of a type that do not have the 'NotMapped' attribute
        /// </summary>
        /// <param name="t">Type to examine for properites</param>
        /// <returns>Array of properties that can be filled</returns>
        public static PropertyInfo[] GetMappedProperties(this Type t)
        {
            NotMappedAttribute mapped = null;
            var props1 = t.GetProperties();
            var props2 = props1
                .Where(p => p.TryGetAttribute<NotMappedAttribute>(out mapped) == false)
                .Select(p => p);
            return props2.ToArray();
        }

        /// <summary>
        /// Get an attribute for a property
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="memberInfo"></param>
        /// <param name="customAttribute"></param>
        /// <returns></returns>
        public static bool TryGetAttribute<T>(this PropertyInfo propertyinfo, out T customAttribute)
            where T : Attribute
        {
            var attributes = propertyinfo.GetCustomAttributes(typeof(T), false).FirstOrDefault();
            if (attributes == null)
            {
                customAttribute = null;
                return false;
            }
            customAttribute = (T)attributes;
            return true;
        }

The key is the TryGetAttribute routine. This returns a true/false based on whether or not an attribute exists on the property (it also returns the attribute, but we don’t use that here). This is used to filter the properties queried from the Type that we’re expecting to load data into. The result is an array of properties that ought to be present in the returned data from the database.

So – how do we get those properties into the object? That’s really the easiest thing of all. The ReadRecord method looks pretty much like anyone would have guessed. In fact, the only reason that this is a separate routine is that I’m using it in several places in my original code.

        /// <summary>
        /// Read data for the current result row from a reader into a destination object, by the name
        /// of the properties on the destination object.
        /// </summary>
        /// <param name="reader">data reader holding return data</param>
        /// <param name="t">object to populate</param>
        /// <returns></returns>
        public static object ReadRecord(this DbDataReader reader, object t, PropertyInfo[] props)
        {
            // copy mapped properties
            foreach (PropertyInfo p in props)
            {
                try
                {
                    // get the requested value from the returned dataset and handle null values
                    var data = reader[p.Name];
                    if (data.GetType() == typeof(System.DBNull))
                        p.SetValue(t, null, null);
                    else
                        p.SetValue(t, reader[p.Name], null);
                }
                catch (Exception ex)
                {
                    if (ex.GetType() == typeof(IndexOutOfRangeException))
                    {
                        // if the result set doesn't have this value, intercept the exception
                        // and set the property value to null / 0
                        p.SetValue(t, null, null);
                    }
                    else
                        // something bad happened, pass on the exception
                        throw ex;
                }
            }

            return t;
        }

Once we have our multiple result sets back from the database, we need to process them. The ResultsList class holds the result sets and provides accessors to each of the individual result sets.

    /// <summary>
    /// Holds multiple Result Sets returned from a Stored Procedure call. 
    /// </summary>
    public class ResultsList : IEnumerable
    {
        // our internal object that is the list of results
        List<List<object>> thelist = new List<List<object>>();

        /// <summary>
        /// Add a results list to the results set
        /// </summary>
        /// <param name="list"></param>
        public void Add(List<object> list)
        {
            thelist.Add(list);
        }

        /// <summary>
        /// Return an enumerator over the internal list
        /// </summary>
        /// <returns>Enumerator over List<object> that make up the result sets </returns>
        public IEnumerator GetEnumerator()
        {
            return thelist.GetEnumerator();
        }

        /// <summary>
        /// Return the count of result sets
        /// </summary>
        public int Count 
        { 
            get { return thelist.Count; } 
        }

        /// <summary>
        /// Get the nth results list item
        /// </summary>
        /// <param name="index"></param>
        /// <returns>List of objects that make up the result set</returns>
        public List<object> this[int index]
        {
            get { return thelist[index]; }
        }

        /// <summary>
        /// Return the result set that contains a particular type and does a cast to that type.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>List of T; if no results match, returns an empty list</returns>
        public List<T> ToList<T>()
        {
            // search each non-empty results list 
            foreach (List<object> list in thelist.Where(p => p.Count > 0).Select(p => p))
            {
                // compare types of the first element - this is why we filter for non-empty results
                if (typeof(T) == list[0].GetType())
                {
                    // do cast to return type
                    return list.Cast<T>().Select(p => p).ToList();
                }
            }

            // no matches? return empty list
            return new List<T>();
        }

        /// <summary>
        /// Return the result set that contains a particular type and does a cast to that type.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>Array of T; if no results match, returns an empty array</returns>
        public T[] ToArray<T>()
        {
            // search each non-empty results list 
            foreach (List<object> list in thelist.Where(p => p.Count > 0).Select(p => p))
            {
                // compare types of the first element - this is why we filter for non-empty results
                if (typeof(T) == list[0].GetType())
                {
                    // do cast to return type
                    return list.Cast<T>().Select(p => p).ToArray();
                }
            }

            // no matches? return empty array
            return new T[0];
        }
    }

So there you have it. A complete package for calling stored procedures that can handle both multiple result sets and returned data in the parameters. Now the question is, how does one go about using this thing???

            using (testentities te = new testentities())
            {
                ParameterList parameters1 = new ParameterList();
                parameters1.Add(new ParameterHolder()
                {
                    Name = "in",
                    Direction = System.Data.ParameterDirection.Input,
                    Value = "asdf",
                    ParameterType = System.Data.DbType.String
                });
                parameters1.Add(new ParameterHolder()
                {
                    Name = "out",
                    Size = 4,
                    Direction = System.Data.ParameterDirection.Output,
                    ParameterType = System.Data.DbType.Int32
                });

                // get a single result set and an output parameter
                var resultsets1 = te.ReadFromStoredProc("dbo.testone", parameters1, typeof(TestOne));
                List<TestOne> set1 = resultsets1.ToList<TestOne>();
                var outparm1 = parameters1.GetValue<Int32>("out");

                // Ignore resultset but get the return code
                ParameterList parameters2 = new ParameterList();
                parameters2.Add(new ParameterHolder()
                {
                    Name = "RC",
                    Size = 4,
                    Direction = System.Data.ParameterDirection.ReturnValue,
                    ParameterType = System.Data.DbType.Int32
                });
                var resultsets2 = te.ReadFromStoredProc("dbo.testtwo", parameters2);
                int rc2 = parameters2.GetValue<int>("RC");

                // Get two resultsets
                var resultset3 = te.ReadFromStoredProc("dbo.testthree", null, typeof(TestOne), typeof(TestTwo));
                List<TestOne> testone3 = resultset3.ToList<TestOne>();
                List<TestTwo> testtwo3 = resultset3.ToList<TestTwo>();

This example shows possible uses of the ReadFromStoredProc routine, showing input and output parameters, accessing the return code value, and how to access individual result sets from the ResultList object.

Update: Improve DbNull handling and catch when a property isn’t present in the result set.

Read Full Post »

This is the first in a series on the development of support for stored procedures in a Code First style. See Code First Stored Procedures for the final product.

One of the biggest (and few) drawbacks to CodeFirst is that it doesn’t support calls to stored procedures. Now, I understand that stored procedures are messy beasts. They can return data accept either single values or tables – or both at the same time – as parameters, and can return multiple results that can be either single values or tables. On the other hand, most stored procedure calls are straightforward. Send over some parameters, get back a table of results. Since Code First doesn’t implement this yet, here’s how to do it for yourself.

First order of business is that this needs to be lightweight. I don’t want to have to load the full EntityFramework into my project just to call a few stored procedures. I want something lighter weight than that. Second order of business is that this needs to work for any “simple” stored procedure that returns a dataset, without having to make a copy for each stored procedure I’m calling.

So, we’re going to write a stored procedure call in the old-fashioned style, but throw in generics so we can re-use this. Since we want to be able to call this with any stored procedure that fits the parameters-in, table-out pattern, we’ll want to make the procedure name and its parameter list to be inputs to our routine. So we begin with:

public static List<T> ReadTableFromStoredProc<T>(this DbContext context,
            String procname,
            IEnumerable<ParmInfo> parms) where T : class

Note that we’re creating an extension method call, off of the DbContext object. This is for a couple of reasons. First, is that the DbContext contains all of the ‘other’ database access routines, so this really belongs here. Second, the DbContext contains the database connection property that we’ll need to make the call to the stored procedure. To handle the list of parameters to the stored procedure, we’re creating a list of ParmInfo objects. The ParmInfo class is declared as:

    public class ParmInfo
    {
        public String Name { get; set; }
        public Object Value { get; set; }
        public System.Data.DbType ParmType { get; set; }
        public Boolean isDbNull { get; set; } // not implemented
        public Boolean outParm { get; set; } // not implemented

        public ParmInfo()
        {
            // set default values
            outParm = false;
            isDbNull = false;
        }
    }

This simple class just holds the information we’ll need to create parameters later in the process. ‘Name’ is, of course, the name of the stored procedure parameter, ‘Value’ is the data being passed in and ‘ParmType’ is an optional value to describe the database type of the Value.

Here’s the main routine. There’s nothing really that interesting about it; the pattern should be familiar to anyone who’s done any old-school database programming.

public static List<T> ReadTableFromStoredProc<T>(this DbContext context,
            String procname,
            IEnumerable<ParmInfo> parms) where T : class
        {
            List<T> result = null;
            var connection = context.Database.Connection;
            try
            {
                connection.Open();
                using (var cmd = connection.CreateCommand())
                {
                    cmd.CommandText = procname;
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    foreach (ParmInfo p in parms)
                        cmd.AddParameter(p.Name, p.Value, p.ParmType);

                    var reader = cmd.ExecuteReader();
                    result = reader.SaveRecord<T>();
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error reading from stored proc" + procname + ": " + ex.Message, ex);
            }
            finally
            {
                connection.Close();
            }

            return result ?? new List<T>();
        }

Basically, we open the database connection, create a command object, and fill it in for calling a stored procedure. The ‘AddParameters’ routine was borrowed from Andy Edinborough. The really interesting bit, though is the ‘reader.SaveRecord<T>();’ call. This routine fills in the list of objects (of whatever type we tell it) using reflection to read values from the database results and store them into the object. Note that since this is outside of the normal DbContext processing, we need to match property names exactly with returned database column names.

The SaveRecord routine creates an object of our generic type, fills in the properties using reflection and then adds the result to a list of that type, which it then returns. Here’s the routine:

public static List<T> SaveRecord<T>(this System.Data.Common.DbDataReader reader)
        {
            List<T> result = new List<T>();
            while (reader.Read())
            {
                T t = (T)(typeof(T).GetConstructor(System.Type.EmptyTypes).Invoke(new object[0]));
                PropertyInfo[] props = t.GetType().GetProperties();
                object[] indexer = null;
                foreach (PropertyInfo p in props)
                {
                    p.SetValue(t, reader[p.Name], indexer);
                }

                result.Add(t);
            }

            return result;
        }

So, all together we have the means to call an ordinary stored procedure quickly and easily. Here’s an example of how to use this:

List<ParmInfo> parms = new List<ParmInfo>();
            parms.Add(new ParmInfo() { Name="code", Value=code, ParmType=System.Data.DbType.String });
            parms.Add(new ParmInfo() { Name="amt", Value=amt, ParmType=System.Data.DbType.Int32 });

            PermitAppEntities pe = new PermitAppEntities();
            return pe.ReadTableFromStoredProc<Fees>("permitapp.requesttotalfees", parms);

The result is a reasonably natural call method that can return a list of whatever object is needed (that matches the stored procedure’s result dataset), and should make a decent ‘stopgap’ until the codefirst guys get their act together. 🙂

Read Full Post »

I’ve started using Razor and ASP.NET MVC3 and Code First for my latest projects and I’ve come across something that’s a bit disappointing. First, let me explain that I *hate* radio buttons that force you to actually hit that tiny, itty bitty, little, narrow spot with your mouse. I like to be able to click either the button or its related text. And, it’s easy to set up the HTML to do this. You simply use the “Label” tag for your text and the “For” attribute to identify the button. Really, truly simple.

OK, to the first annoyance. I’ve created a nifty script (in an earlier post) to create lists of radio buttons from SelectLists. Works like a charm, and creates the Label tags correctly. However, since I’ve started using Razor, I’ve discovered that my script does not include the tags for client-side verification (this is a topic for another day). So, what to do? First I go back to the old, built in “RadioButtonFor” helper and that’s OK, except that it generates radio buttons only. It won’t generate the “Label” tag that I like. And, it gets better. It creates the radio buttons in such a way that my trick with the “Label” tags won’t work. Isn’t that special?

The key to making my “Label” trick work is that the radio button controls need to have a unique ID attribute. Fortunately, we can force the old-style “RadioButtonFor” helper to provide a unique id, but we’re going to have to do it all by hand. Here’s the code to make it work:

@Html.RadioButtonFor(model => model.requirements, “Y”, new { id = “requirements_0″ })<label
for=”requirements_0″>Yes</label>

@Html.RadioButtonFor(model => model.requirements, “N”, new { id = “requirements_1″ })<label
for=”requirements_1″>No</label>

You can see that we’re manually setting the ID’s in the RadioButtonFor helper, then referencing them in the Label and all is well. Except this is as ugly as homemade sin. So much for MVC and elegant HTML.

Oi.

Edit: And, finally a bit of good news. While my existing RadioButtonListFor class does not work with client-side validation, it still works well with the server side validations so all is not lost and my class remains (somewhat) useful for the time being.

Read Full Post »

First, let me say that I really like Microsoft’s MVC development products. They’re (for me!) easy and natural to use and make for an enjoyable development experience. Isn’t that what we all want? Still, there are gaps, holes, things missing that shouldn’t be, etc. Here’s one of them: There are nice helper routines to construct list boxes and dropdown lists based on the SelectList class, but no easy way to construct a list of radio buttons. You’re stuck coding all of them by hand in your html code file. Not only is this ugly and counter-intuitive, it badly clutters the HTML file with lots of inline code. Yes, there’s a place for inline code in the HTML file – this isn’t it.

The solution, of course, is to write your own extension method. So how to do this? First problem is knowing how to create an extension method. That’s pretty easy. You define a class with static methods (yes, they must be static) that have the first parameter named “this” with a type of the class you’re trying to extend. An example of a simple class to help build image tags is:

        public static MvcHtmlString Image(this HtmlHelper helper, string id, string url, string alternateText, object htmlAttributes)
        {
            // Instantiate a UrlHelper
            var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

            // Create tag builder
            var builder = new TagBuilder("img");

            // Create valid id
            builder.GenerateId(id);

            // Add attributes
            builder.MergeAttribute("src", urlHelper.Content(url));
            builder.MergeAttribute("alt", alternateText);
            builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));

            // Render tag
            return MvcHtmlString.Create(builder
                .ToString(TagRenderMode.SelfClosing));
        }

Since the first parameter is of type HtmlHelper, this method is an extension to the HtmlHelper class. It looks and acts like any other static method available on the HtmlHelper class. To use this class, you call it like you do any other HtmlHelper method:

<%= Html.Image("CountySeal","~/Content/images/CountySeal-Full Color_90x90.jpg", "County Seal") %>

Html helper methods are required to return a string containing the constructed HTML that will be substituted inline for the method call. You can see in the Image method, that we’re building the HTML code for an image element, including the alt text. Since the parameters are required, you won’t be forgetting to put alt text on your “img” tags if you use this method.

So, how to do a radio button list? The pattern I want to emulate is the xxxxxxFor<>(property, valuelist, <other parms> ) helper methods. An example of this type of Helper is

<%: Html.DropDownListFor<WaterHeaterData, String>(model=>model.heatertype, Model.heatertypelist) %>

Since it’s important that we write our code only once, we’ll be using generics to create code that can be used for any model and property. The output of the radio button list method should be a sequence of “input” elements and “label” elements in proper HTML code (that’s the point of doing this, isn’t it?) More importantly, we want to have the selected radio button value show up in our model property when the page is posted back to the server. Here’s what our radio button list method call should look like:

<%: Html.RadioButtonListFor<WaterHeaterData, String>(model=>model.requirements, Model.requirementslist) %>

Note that first parameter. It’s not your ordinary string or int. Just a little poking around gives you this signature for that parameter:

Expression<Func<TModel, TProperty>> property

Not the easiest thing in the world to interpret. It’s a lambda expression providing a function (or ‘delegate’) on the Model that returns a type of TProperty. In the Html.DropDownListFor example just above, TProperty is a String. If you don’t know what a lambda expression is, I suggest looking them up – LINQ is one of the few things to come along in recent years that have actually changed how I write programs. Anyway, we can now start to construct our helper method to generate a list of radio buttons. Remember, we want to take a list of possible values from a SelectList, and it would be nice to be able to provide some styling to apply to the radio button and to its text label. Since we’re going to create a list of radio buttons, it would also be nice to include a separator string as well. This is the result:

        public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
                this HtmlHelper<TModel> helper,
                Expression<Func<TModel, TProperty>> property,
                SelectList list,
                String separator = "",
                object inputhtmlAttributes = null,
                object labelhtmlAttributes = null
            )

We’ve got our proper generic input model and property type declarations so we can use our method with any model and any type of property. Note that the first parameter is not just an HtmlHelper, but has a type specifier on it. The second parameter is our property delegate which is followed by our SelectList. We then have our separator string for between the radio buttons and finally we include the ability to provide classes, styling or whathaveyou for both the radio button input control and the associated label.

The next problem is how to get from a delegate for our property to both the property name and property value. Remember, we want ASP.NET MVC’s processing to automatically place the selected radio button value back into our property. That means naming the radio buttons with the property name. We also want the current property value to show up as the selected radio button and that means getting access to the property value. This is the point at which some serious digging gets glossed over. Essentially, we can use the model metadata accessible through the Lambda expression to get to our name and value.

            // get the model metadata and verify we found something
            var modelmetadata = ModelMetadata.FromLambdaExpression(property, helper.ViewData);
            if (null == modelmetadata) throw new NotFoundException(property.ToString() + " Not Found");

            // get the property value and name from the metadata.
            var value = modelmetadata.Model ?? default(TProperty);
            var name = modelmetadata.PropertyName;

Once we have our value and SelectList figured out, we want to enable the currently selected item to be selected in the radio button list. To do that, we need to know “what’s currently selected”. Since the input value could be null, we check for that and, if it is null, we use the default “selected” item in the SelectList.

            // convert the value to a String for comparison with the SelectList contents.
            String selected = (null != value)
                ? value.ToString()
                : (null != list.SelectedValue) ? list.SelectedValue.ToString() : String.Empty;

I’m using the generic ‘var’ type for the value since I can’t predict what type it will be. I’m also checking for null at several points along the way. Defensive programming is your friend! Once we have these two things, the rest just falls into place. Here’s the final routine

        /// <summary>
        /// Create a radio button list from a Selectlist of options and a lambda referencing a
        /// model property.
        /// </summary>
        /// <typeparam name="TModel">Data entity type of your Model</typeparam>
        /// <typeparam name="TProperty">Data type of the property</typeparam>
        /// <param name="helper"></param>
        /// <param name="property">Lambda referencing the property of the model that will be the selected item/output of the selection</param>
        /// <param name="list">SelectList of properties</param>
        /// <param name="separator">Html to put between radio button/label pairs</param>
        /// <param name="inputhtmlAttributes">Styling for the button</param>
        /// <param name="labelhtmlAttributes">Styling for the label</param>
        /// <returns></returns>
        public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
                this HtmlHelper<TModel> helper,
                Expression<Func<TModel, TProperty>> property,
                SelectList list,
                String separator = "",
                object inputhtmlAttributes = null,
                object labelhtmlAttributes = null
            )
        {
            // get the model metadata and verify we found something
            var modelmetadata = ModelMetadata.FromLambdaExpression(property, helper.ViewData);
            if (null == modelmetadata) throw new NotFoundException(property.ToString() + " Not Found");

            // get the property value and name from the metadata.
            var value = modelmetadata.Model ?? default(TProperty);
            var name = modelmetadata.PropertyName;

            // convert the value to a String for comparison with the SelectList contents.
            String selected = (null != value)
                ? value.ToString()
                : (null != list.SelectedValue) ? list.SelectedValue.ToString() : String.Empty;


            // build the output html for the radiobuttons and their labels.
            StringBuilder outstr = new StringBuilder();
            int counter = 0;
            foreach (SelectListItem item in list)
            {
                string id = name + "_" + counter.ToString();
                counter++;

                // the radio button
                TagBuilder input = new TagBuilder("input");
                input.Attributes.Add("id", id);
                input.Attributes.Add("name", name);
                input.Attributes.Add("type", "radio");
                input.Attributes.Add("value", item.Value);
                if (selected == item.Value || selected == item.Text)
                    input.Attributes.Add("checked", "checked");
                if (null != inputhtmlAttributes)
                    input.MergeAttributes(new RouteValueDictionary(inputhtmlAttributes));
                outstr.Append(input.ToString(TagRenderMode.SelfClosing));

                // the label
                TagBuilder label = new TagBuilder("label");
                label.Attributes.Add("for", id);
                label.InnerHtml = item.Text;
                if (null != labelhtmlAttributes)
                    label.MergeAttributes(new RouteValueDictionary(labelhtmlAttributes));
                outstr.Append(label.ToString(TagRenderMode.Normal));

                // add the separator
                outstr.Append(separator);
            }

            return MvcHtmlString.Create(outstr.ToString());
        }

Hopefully, this will be useful to you! Enjoy!

Update: Changed the selected item logic to choose the selected item from the input SelectList when the input value is null.

Read Full Post »