<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Den Of Ubiquity &#187; C#</title>
	<atom:link href="http://www.denofubiquity.com/tag/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.denofubiquity.com</link>
	<description>Buzzword-enriched Software Development Content</description>
	<lastBuildDate>Sun, 27 Sep 2009 20:10:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.3</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Storing URIs in SQL Server 2008 using the HIERARCHYID datatype and LINQ-To-SQL</title>
		<link>http://www.denofubiquity.com/software-development/storing-uris-in-sql-server-2008-using-the-hierarchyid-datatype-and-linq-to-sql/</link>
		<comments>http://www.denofubiquity.com/software-development/storing-uris-in-sql-server-2008-using-the-hierarchyid-datatype-and-linq-to-sql/#comments</comments>
		<pubDate>Wed, 14 May 2008 14:47:41 +0000</pubDate>
		<dc:creator>ijonas</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[code samples]]></category>
		<category><![CDATA[HierarchyId]]></category>
		<category><![CDATA[HOWTO]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[LINQ-To-SQL]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://ijonas.wordpress.com/?p=96</guid>
		<description><![CDATA[I&#8217;ve been playing around with SQL Server 2008 CTP, exploring the benefits of the new HIERARCHYID datatype, which has been designed to efficiently store depth-first tree structures in SQL Server 2008.
My requirements were to store URI paths such as ones you might find in URLs, whereby each path component is held as a separate record in a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been playing around with SQL Server 2008 CTP, exploring the benefits of the new HIERARCHYID datatype, which has been designed to efficiently store depth-first tree structures in SQL Server 2008.</p>
<p>My requirements were to store URI paths such as ones you might find in URLs, whereby each path component is held as a separate record in a table. Each path component refers to a folder in file system, e.g.</p>
<pre><strong>URL:</strong> http://www.vamosa.com/index/information_solutions/technology_and_products/vamosa_content_migrator.htm
<strong>URI:</strong> path: /index/information_solutions/technology_and_products/vamosa_content_migrator.htm</pre>
<p>So traditionally in the database I would end up with parent/child relationship as such</p>
<pre><strong>id 	label					parent_id
</strong>0	NULL					NULL		&lt;--- root element
1	index					0
2	information_solutions			1
3	technology_and_products			2
4	vamosa_content_migration.htm	<span style="white-space:pre;">	</span>3</pre>
<p>HIERARCHYID allows you to perform all sorts of fast hiearchical queries without having to wander up and down the parent/child foreign key relationship. Those are the benefits, however there&#8217;s a problem&#8230;</p>
<p>At the time of writing the .NET Framework 3.5&#8217;s System.Data.SqlTypes namespace does not provide any support for HIERARCHID datatypes, e.g. SqlHierarchId as a class is missing, meaning that if you want to work with the new type you&#8217;ll need hide it from your .NET code using stored procedures, and that&#8217;s the approach I&#8217;ve taken in this post.</p>
<p>The other thing to be aware of is that the HIERARCHYID column is not a foreign key to a record further up the tree. The HIERARCHYID column stores position of the current record within the tree, e.g.</p>
<pre><strong>id  </strong><span style="white-space:pre;"><strong>	</strong></span><strong>label					hierarchyid_field.ToString()
</strong>0	NULL					/	<span style="white-space:pre;">	</span>&lt;--- root element
1	index					/1/
2	information_solutions			/1/1/
3	technology_and_products			/1/1/1/
4	vamosa_content_migrator.htm		/1/1/1/1/</pre>
<p>The table I&#8217;ve created is called URI and is defined as follows:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> dbo<span style="color: #66cc66;">.</span>URI
<span style="color: #66cc66;">&#40;</span>
	Id uniqueidentifier <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
	Label nvarchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">256</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
	UriHID hierarchyid <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>           <span style="color: #808080; font-style: italic;">-- the magical new datatype</span>
	CONSTRAINT <span style="color: #66cc66;">&#91;</span>PK_URI<span style="color: #66cc66;">&#93;</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>
<span style="color: #66cc66;">&#41;</span></pre></td></tr></table></div>

<p>I want to be able call my stored proc as follows:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">  MyLINQDataContext db <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MyLINQDataContext<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// a previously defined context via .dbml file</span>
  <span style="color: #003399;">System</span>.<span style="color: #006633;">Guid</span><span style="color: #339933;">?</span> uri_id<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>			  <span style="color: #666666; font-style: italic;">// variable to capture the URI.Id of the last node inserted</span>
  db.<span style="color: #006633;">InsertURI</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/products/vcm/index.html&quot;</span>, ref uri_id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	<span style="color: #666666; font-style: italic;">// call to stored proc</span>
  Console.<span style="color: #006633;">Out</span>.<span style="color: #006633;">Writeline</span><span style="color: #009900;">&#40;</span> uri_id <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>		 <span style="color: #666666; font-style: italic;">// doing something useful with the return result</span></pre></td></tr></table></div>

<p>Stored procedures aren&#8217;t my strongest point by a long stretch so feel free to comment and improve the code, but here&#8217;s the InsertURI stored proc:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> Procedure InsertURI
	@uri nvarchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">4000</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
	@uri_id uniqueidentifier OUTPUT
<span style="color: #993333; font-weight: bold;">AS</span>
	declare @root_uri_id uniqueidentifier
	declare @path_remainder nvarchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">4000</span><span style="color: #66cc66;">&#41;</span>
	declare @pos_slash int
	declare @parent_uri_hid HIERARCHYID
&nbsp;
	<span style="color: #993333; font-weight: bold;">SET</span> @parent_uri_hid <span style="color: #66cc66;">=</span> HIERARCHYID::GetRoot<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">-- ensure the root exists</span>
	<span style="color: #993333; font-weight: bold;">SELECT</span> @root_uri_id <span style="color: #66cc66;">=</span> u<span style="color: #66cc66;">.</span>id <span style="color: #993333; font-weight: bold;">FROM</span> URI u <span style="color: #993333; font-weight: bold;">WHERE</span> u<span style="color: #66cc66;">.</span>label <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span>
	<span style="color: #993333; font-weight: bold;">IF</span> @root_uri_id <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span>
		<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> URI <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>NEWID<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span> @parent_uri_hid<span style="color: #66cc66;">&#41;</span>
&nbsp;
	<span style="color: #993333; font-weight: bold;">SET</span> @path_remainder <span style="color: #66cc66;">=</span> @uri
	<span style="color: #993333; font-weight: bold;">SET</span> @pos_slash <span style="color: #66cc66;">=</span> charindex<span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">,</span> @path_remainder <span style="color: #66cc66;">&#41;</span>
	while <span style="color: #66cc66;">&#40;</span>len<span style="color: #66cc66;">&#40;</span>@path_remainder<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>
	begin
		declare @next_slash int
		declare @uri_label nvarchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">256</span><span style="color: #66cc66;">&#41;</span>
		declare @current_uri_hid HIERARCHYID
		<span style="color: #993333; font-weight: bold;">SET</span> @next_slash <span style="color: #66cc66;">=</span> charindex<span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">,</span> @path_remainder<span style="color: #66cc66;">,</span> @pos_slash<span style="color: #66cc66;">+</span><span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">&#41;</span>
&nbsp;
		<span style="color: #808080; font-style: italic;">-- determine the next label in the sequence of depth-first node names</span>
		<span style="color: #993333; font-weight: bold;">IF</span> @next_slash <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span>
		begin
			<span style="color: #993333; font-weight: bold;">SET</span> @uri_label <span style="color: #66cc66;">=</span> SUBSTRING<span style="color: #66cc66;">&#40;</span> @path_remainder<span style="color: #66cc66;">,</span> @pos_slash<span style="color: #66cc66;">+</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> @next_slash <span style="color: #66cc66;">-</span> @pos_slash <span style="color: #66cc66;">-</span> <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">&#41;</span>
			<span style="color: #993333; font-weight: bold;">SET</span> @path_remainder <span style="color: #66cc66;">=</span> substring<span style="color: #66cc66;">&#40;</span> @path_remainder<span style="color: #66cc66;">,</span> @next_slash<span style="color: #66cc66;">,</span> len<span style="color: #66cc66;">&#40;</span>@path_remainder<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>
		end
		else
		begin
			<span style="color: #993333; font-weight: bold;">SET</span> @uri_label <span style="color: #66cc66;">=</span> SUBSTRING<span style="color: #66cc66;">&#40;</span> @path_remainder<span style="color: #66cc66;">,</span> @pos_slash<span style="color: #66cc66;">+</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> len<span style="color: #66cc66;">&#40;</span>@path_remainder<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>
			<span style="color: #993333; font-weight: bold;">SET</span> @path_remainder <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">''</span>
		end
		<span style="color: #993333; font-weight: bold;">SET</span> @pos_slash <span style="color: #66cc66;">=</span> charindex<span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">,</span> @path_remainder <span style="color: #66cc66;">&#41;</span>
		<span style="color: #808080; font-style: italic;">-- determine if current @uri_label exists as child of @parent_uri_hid</span>
		<span style="color: #993333; font-weight: bold;">SET</span> @current_uri_hid <span style="color: #66cc66;">=</span> <span style="color: #993333; font-weight: bold;">NULL</span>
		<span style="color: #993333; font-weight: bold;">SELECT</span> @current_uri_hid <span style="color: #66cc66;">=</span> u<span style="color: #66cc66;">.</span>UriHID <span style="color: #993333; font-weight: bold;">FROM</span> URI u <span style="color: #993333; font-weight: bold;">WHERE</span> u<span style="color: #66cc66;">.</span>UriHID<span style="color: #66cc66;">.</span>GetAncestor<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">=</span> @parent_uri_hid <span style="color: #993333; font-weight: bold;">AND</span> u<span style="color: #66cc66;">.</span>Label<span style="color: #66cc66;">=</span>@uri_label
		<span style="color: #993333; font-weight: bold;">IF</span> @current_uri_hid <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span>
		begin
			<span style="color: #808080; font-style: italic;">-- the label doesn't exist as a child, hence create it</span>
			<span style="color: #808080; font-style: italic;">-- first determine the new hierarchyid - new node will be last in row of siblings</span>
			declare @last_child_uri_hid HIERARCHYID
			<span style="color: #993333; font-weight: bold;">SELECT</span> @last_child_uri_hid <span style="color: #66cc66;">=</span> MAX<span style="color: #66cc66;">&#40;</span>UriHID<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> URI u <span style="color: #993333; font-weight: bold;">WHERE</span> u<span style="color: #66cc66;">.</span>UriHID<span style="color: #66cc66;">.</span>GetAncestor<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">=</span> @parent_uri_hid
			<span style="color: #993333; font-weight: bold;">SET</span> @current_uri_hid <span style="color: #66cc66;">=</span> @parent_uri_hid<span style="color: #66cc66;">.</span>GetDescendant<span style="color: #66cc66;">&#40;</span>@last_child_uri_hid<span style="color: #66cc66;">,</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
			<span style="color: #993333; font-weight: bold;">SET</span> @uri_id <span style="color: #66cc66;">=</span> NEWID<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
			<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> uri <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>@uri_id<span style="color: #66cc66;">,</span> @uri_label<span style="color: #66cc66;">,</span> @current_uri_hid <span style="color: #66cc66;">&#41;</span>
		end
		<span style="color: #993333; font-weight: bold;">SET</span> @parent_uri_hid <span style="color: #66cc66;">=</span> @current_uri_hid
	end</pre></td></tr></table></div>

<p>The stored proc takes the @uri string and chops it using the &#8216;/&#8217;-separator (orange highlighted), looping through each element in the path (red brown highlighted), first &#8216;index&#8217; then &#8216;information_solutions&#8217;, etc. For each element it will check wether or not the element exists (red highlighted code), creating it if necessary (purple highlighted). The position of the new node will always be on the &#8216;far right&#8217; of its siblings (green highlighted code).<br />
 </p>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.denofubiquity.com/software-development/storing-uris-in-sql-server-2008-using-the-hierarchyid-datatype-and-linq-to-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
