<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Alex Sarafian as Developer &#187; Typed DataSet</title>
	<atom:link href="http://sarafianalex.wordpress.com/tag/typed-dataset/feed/" rel="self" type="application/rss+xml" />
	<link>http://sarafianalex.wordpress.com</link>
	<description>Adventures in C# Land and some SQL</description>
	<lastBuildDate>Fri, 04 Sep 2009 11:27:50 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='sarafianalex.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/ea38bb69738d229a89ab00b82aad64b7?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Alex Sarafian as Developer &#187; Typed DataSet</title>
		<link>http://sarafianalex.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://sarafianalex.wordpress.com/osd.xml" title="Alex Sarafian as Developer" />
		<item>
		<title>Typed Dataset &lt;&#8211;&gt; Linq Entities</title>
		<link>http://sarafianalex.wordpress.com/2008/04/21/typed-dataset-linq-entities/</link>
		<comments>http://sarafianalex.wordpress.com/2008/04/21/typed-dataset-linq-entities/#comments</comments>
		<pubDate>Mon, 21 Apr 2008 09:51:20 +0000</pubDate>
		<dc:creator>Sarafian Alex</dc:creator>
				<category><![CDATA[.NET C#]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Typed DataSet]]></category>

		<guid isPermaLink="false">http://sarafianalex.wordpress.com/2008/04/21/typed-dataset-linq-entities/</guid>
		<description><![CDATA[Introduction
On my previous post I discussed about how LINQ entities to not fit the world of applications that do not have a constant access to the data source. I concluded that if there was a way to connect Linq Entities and Type Dataset, then the domain of Web Applications and N-Tier Applications could be supported [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sarafianalex.wordpress.com&blog=2367780&post=21&subd=sarafianalex&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><h2>Introduction</h2>
<p>On my previous <a href="http://sarafianalex.wordpress.com/2008/04/21/linq-and-client-server-applications/">post</a> I discussed about how LINQ entities to not fit the world of applications that do not have a constant access to the data source. I concluded that if there was a way to connect Linq Entities and Type Dataset, then the domain of Web Applications and N-Tier Applications could be supported by the same Bussiness Object Model and a Data Access Layer over LINQ.</p>
<h2>Assumptions &#8211; Prerequisites</h2>
<h3>Entity and Data Table Naming</h3>
<p>Before I continue there is a basic assumption that must be kept in mind. The Business Object Model and the Typed Dataset must be constructed by their respective designer in Visual Studio, by dragging the tables into each designer. The main reason is, that the converter I have developed, assumes that the corresponding entities in LINQ and table in the Dataset have the same name.</p>
<h3>Relations and Foreign Key Constraints</h3>
<p>Also every relation between entities must have the same name as that between tables in the dataset. The above are automatically (great coincidence) kept, just by using the designer.</p>
<p>Circular Relations and all combinations have not been tested, so I do not know whether my code supports them</p>
<h3>Database construction From LINQ</h3>
<p>If you wish to construct the database schema from the LINQ designer then just do so, but before creating the typed dataset, the database must be created. To do this just call</p>
<blockquote><div><span style="color:#2b91af;">LinqTestDataContext </span>ltdc = <span style="color:#0000ff;">new </span><span style="color:#2b91af;">LinqTestDataContext</span>(connectionString); <span style="color:#0000ff;">if </span>(!ltdc.DatabaseExists()) { ltdc.CreateDatabase(); }</div>
</blockquote>
<p>where <span style="color:#777777;"><span style="color:#2b91af;">LinqTestDataContext </span></span>is the DataContext the designer has created.</p>
<h3>Column Prerequisite</h3>
<p>Each entity must have a version property. This is because Attach(entity,true) only works if there is such a property.</p>
<h2>The Database Schema used for testing</h2>
<p>The LINQ schema is name LinqTest and its dataset represantion DsLinqTest.</p>
<p>As seen in the picture below there is a RootElement with a unique key ID, a version property TimeStamp and two string properties.</p>
<p>RootElement has child relation of SubRootElement entities which also have a unique key ID, a version property TimeStamp a string property and a RootID foreign key pointing to the RootElement it belongs</p>
<p><a href="http://sarafianalex.files.wordpress.com/2008/04/image.png"><img style="border-width:0;" height="135" alt="image" src="http://sarafianalex.files.wordpress.com/2008/04/image-thumb.png?w=395&#038;h=135" width="395" border="0"></a></p>
<p>The corresponding Dataset will be. The relation name is the same, even thought it is not showing on the above image.</p>
<p><a href="http://sarafianalex.files.wordpress.com/2008/04/image1.png"><img style="border-width:0;" height="110" alt="image" src="http://sarafianalex.files.wordpress.com/2008/04/image-thumb1.png?w=396&#038;h=110" width="396" border="0"></a></p>
<p>Each of the Business Object are in a separate assembly.</p>
<h2>DataSetEntityConvertion</h2>
<p>This is name of the assembly that does the convention between an LINQ Business Object and a Typed Dataset assuming that the above prerequisites are met.</p>
<p>The assembly uses heavily reflection and generics so the understanding of the above must be at least good.</p>
<p>Keep in mind that since the dataset is typed, every type in the dataset is specifically named so it can be used to discover the entities it relates to.</p>
<h3>ToDataRow</h3>
<p>Is the part where entities are used to fill the appropriate tables in the dataset.</p>
<p>The entry point is the <span style="color:#2b91af;">Entity2DataSet</span> class, where TEntity is the entity type and TDataSet is the dataset type. In our case RootElement and DsLinqTest respectively.</p>
<p>Basically the <span style="color:#2b91af;">Entity2DataSet</span> class discovers the table that corresponds to the entity, and then calls the <span style="color:#2b91af;">Entity2DataRow </span>class which in addition takes the DataTable type discovered.</p>
<p>There are some helping functions that through reflection fill the row, from the entity and also find the child relations of the entity if there are any. If that is true the <span style="color:#2b91af;">Entity2DataSet</span> class is called again but this time TEntity should be SubRootElement in our case.</p>
<p>This side of the convention is fairly easy.</p>
<h3>ToEntity</h3>
<p>This case deals with converting a whole dataset to its entity. The entry class is <span style="color:#2b91af;">DataSet2Entity </span>where TDataContext is the type of our DataContext and TDataSet the type of the source Dataset. In our case LinqTestBigDataContext and DsLinqTest respectively.</p>
<p>The first thing that <span style="color:#2b91af;">DataSet2Entity </span>does is to find the tables have no parent relations. For each of these tables <span style="color:#2b91af;">DataTable2Entity </span>is used where in addition TDataTable and TDataRow are the types of the table and its rows.</p>
<p><span style="color:#2b91af;">DataTable2Entity </span>discovers the entity type that must create for each row it has and does so by using <span style="color:#2b91af;">DataRow2Entity</span> which is supplied with the knowledge of whether it is child row or not. This is crucial because if it is child row, it must be added to the related EntitySet of its parent entity instead of the entity Table in the data context.</p>
<p>The trick here is to know whether the original row is Added,Modified, Deleted or unchanged which is the easy part through RowState. The hard part is what to do with it.</p>
<h5>Added</h5>
<p>This case is easy. Just construct the entity and add it the table or the entityset and call InsertOnSubmit.</p>
<h5>Modified or Unmodified</h5>
<p>Here start the problems. First we must acquire the entity it self to which we will apply the values. Accordingly to if the row is a child or not, a predicate function or expression must be constructed. This part was the most difficult.</p>
<p>If the row is unmodified then there will be no applying of values.</p>
<h5>Deleted</h5>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Like in Modified the entity must be retrieved from the entitytable of the datacontext in order to call DeleteOnSubmit.</p>
<h3>Keeping track of the changes</h3>
<p>When a row is inserted or modified, various column values need to be updated by the auto generated ones from the database. So in every entity the PropertyChanged is captured. There with the help of a dictionary the new values are applied to the original rows. This happens after the SubmitChanges of the datacontext is used.</p>
<p>The rest of the <span style="color:#2b91af;">DataRow2Entity</span> finds the child rows of the row for each data relation and calls another generic version of its self.</p>
<h2>Creating Predicate Functions and Expressions</h2>
<p>This was the hardest part, and still there are some point that I can&#8217;t understand.</p>
<p>When trying to acquire an entity from the table entity of the datacontext, a simple delegate function suffices. After many attempts a managed to make the creation entirely dynamic based on the primary keys of the entity.</p>
<p>This is done by these two functions</p>
<blockquote><div><span style="color:#0000ff;">private </span>System.<span style="color:#2b91af;">Func</span>&lt;TEntity, <span style="color:#0000ff;">bool</span>&gt; CreatePredicateFunction(TDataRow row) { <span style="color:#0000ff;">return </span>p =&gt; (IsEqual(p, row)); } <span style="color:#0000ff;">private bool </span>IsEqual(TEntity entity, TDataRow row) { <span style="color:#0000ff;">for </span>(<span style="color:#0000ff;">int </span>i = 0; i &lt; Cache.<span style="color:#2b91af;">EntityPrimaryKeys</span>&lt;TEntity&gt;.Names.Count; i++) { <span style="color:#0000ff;">object </span>columnValue = <span style="color:#0000ff;">null</span>; <span style="color:#0000ff;">if </span>(row.RowState == <span style="color:#2b91af;">DataRowState</span>.Deleted) { columnValue = row[Cache.<span style="color:#2b91af;">EntityPrimaryKeys</span>&lt;TEntity&gt;.Names[i], <span style="color:#2b91af;">DataRowVersion</span>.Original]; } <span style="color:#0000ff;">else </span>{ columnValue = row[Cache.<span style="color:#2b91af;">EntityPrimaryKeys</span>&lt;TEntity&gt;.Names[i]]; } <span style="color:#0000ff;">if </span>((<span style="color:#0000ff;">bool</span>)Cache.<span style="color:#2b91af;">EntityPrimaryKeys</span>&lt;TEntity&gt;.EqualMethods[i].Invoke(<span style="color:#0000ff;">this</span>.entityType.GetProperty(Cache.<span style="color:#2b91af;">EntityPrimaryKeys</span>&lt;TEntity&gt;.Names[i]).GetValue(entity, <span style="color:#0000ff;">null</span>), <span style="color:#0000ff;">new object</span>[] { columnValue }) == <span style="color:#0000ff;">false</span>) { <span style="color:#0000ff;">return false</span>; } } <span style="color:#0000ff;">return true</span>; }</div>
</blockquote>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Happy as I was that I will be able to cast the above to an <span style="color:#2b91af;">Expression</span>&lt;System.<span style="color:#2b91af;">Func</span>&lt;TEntity, <span style="color:#0000ff;">bool</span>&gt;&gt; I found out that at runtime an exception is thrown telling me that IsEqual cannot be converted or something.</p>
<p>I assume the Expression is something far more complicated than a delegate. So in order for this to work a CreatePredicateExpression must by supplied in every DataRow of our dataset. I did like this</p>
<blockquote><p><span style="color:#0000ff;">public static class </span><span style="color:#2b91af;">DsLinqTestPredicators </span>{ <span style="color:#0000ff;">public static </span><span style="color:#2b91af;">Expression</span>&lt;System.<span style="color:#2b91af;">Func</span>&lt;<span style="color:#2b91af;">RootElement</span>, <span style="color:#0000ff;">bool</span>&gt;&gt; CreatePredicateExpression(<span style="color:#2b91af;">DsLinqTest</span>.<span style="color:#2b91af;">RootElementRow </span>row) { <span style="color:#0000ff;">int </span>idValue = row.RowState == System.Data.<span style="color:#2b91af;">DataRowState</span>.Deleted ? (<span style="color:#0000ff;">int</span>)row[<span style="color:#a31515;">"ID"</span>, System.Data.<span style="color:#2b91af;">DataRowVersion</span>.Original] : row.ID; <span style="color:#0000ff;">return </span>(<span style="color:#2b91af;">Expression</span>&lt;System.<span style="color:#2b91af;">Func</span>&lt;<span style="color:#2b91af;">RootElement</span>, <span style="color:#0000ff;">bool</span>&gt;&gt;)(p =&gt; p.ID.Equals(idValue)); } <span style="color:#0000ff;">public static </span><span style="color:#2b91af;">Expression</span>&lt;System.<span style="color:#2b91af;">Func</span>&lt;<span style="color:#2b91af;">SubRootElement</span>, <span style="color:#0000ff;">bool</span>&gt;&gt; CreatePredicateExpression(<span style="color:#2b91af;">DsLinqTest</span>.<span style="color:#2b91af;">SubRootElementRow </span>row) { <span style="color:#0000ff;">int </span>idValue = row.RowState == System.Data.<span style="color:#2b91af;">DataRowState</span>.Deleted ? (<span style="color:#0000ff;">int</span>)row[<span style="color:#a31515;">"ID"</span>, System.Data.<span style="color:#2b91af;">DataRowVersion</span>.Original] : row.ID; <span style="color:#0000ff;">return </span>(<span style="color:#2b91af;">Expression</span>&lt;System.<span style="color:#2b91af;">Func</span>&lt;<span style="color:#2b91af;">SubRootElement</span>, <span style="color:#0000ff;">bool</span>&gt;&gt;)(p =&gt; p.ID.Equals(idValue)); } }</p>
</blockquote>
<h2>Final Words for the Converter</h2>
<p>Extension Methods are heavily used to help making the convertion as programmatically tranparent as possible.</p>
<h2>Using the Code</h2>
<h3><span style="color:#0000ff;"><span style="color:#333333;">Extenders</span></span></h3>
<blockquote><p><span style="color:#0000ff;">public static class</span><span style="color:#2b91af;">DsLinqTestExtenders<br /></span>{<br />&nbsp;&nbsp;&nbsp; <span style="color:#0000ff;">public static void</span>Insert(<span style="color:#0000ff;">this</span><span style="color:#2b91af;">DsLinqTest </span>extented, <span style="color:#0000ff;">object</span>entity)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((<span style="color:#2b91af;">DataSet</span>)extented).Insert(entity);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; <span style="color:#0000ff;">public static void</span>Insert(<span style="color:#0000ff;">this</span><span style="color:#2b91af;">DsLinqTest </span>extented, <span style="color:#0000ff;">object</span>[] entities)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((<span style="color:#2b91af;">DataSet</span>)extented).Insert(entities);<br />&nbsp;&nbsp;&nbsp; }</p>
<p><span style="color:#0000ff;">public static void</span>ToEntities(<span style="color:#0000ff;">this</span><span style="color:#2b91af;">DsLinqTest </span>extented, <span style="color:#2b91af;">DataContext </span>dataContext)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((<span style="color:#2b91af;">DataSet</span>)extented).ToEntities(dataContext);</p>
<p>}<br />}</p>
</blockquote>
<p><a href="http://11011.net/software/vspaste"></a></p>
<h3>Entity2Dataset</h3>
<blockquote><p><span style="color:#0000ff;">public </span><span style="color:#2b91af;">DsLinqTest </span>GetDsFromID(<span style="color:#0000ff;">int </span>id) { <span style="color:#2b91af;">LinqTestDataContext </span>ltdc = <span style="color:#0000ff;">new </span><span style="color:#2b91af;">LinqTestDataContext</span>(connectionString); <span style="color:#2b91af;">RootElement </span>re = ltdc.RootElements.Single(p =&gt; p.ID.Equals(id)); <span style="color:#2b91af;">DsLinqTest </span>ds = <span style="color:#0000ff;">new </span><span style="color:#2b91af;">DsLinqTest</span>(); ds.Insert(re); ds.AcceptChanges(); <span style="color:#0000ff;">return </span>ds;}</p>
</blockquote>
<p><a href="http://11011.net/software/vspaste"></a></p>
<h3>DataSet2Entity</h3>
<blockquote><p><span style="color:#0000ff;">public void </span>SaveGeneralDs(<span style="color:#2b91af;">DsLinqTest </span>dsLinqTest) { <span style="color:#2b91af;">LinqTestDataContext </span>ltdc = <span style="color:#0000ff;">new </span><span style="color:#2b91af;">LinqTestDataContext</span>(connectionString); dsLinqTest.ToEntities(ltdc); ltdc.SubmitChanges(); }</p>
</blockquote>
<p><a href="The assemblies will be upload when I post the codeproject article.">Source Code for the above assemblies</a></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/sarafianalex.wordpress.com/21/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/sarafianalex.wordpress.com/21/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sarafianalex.wordpress.com/21/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sarafianalex.wordpress.com/21/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sarafianalex.wordpress.com/21/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sarafianalex.wordpress.com/21/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sarafianalex.wordpress.com/21/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sarafianalex.wordpress.com/21/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sarafianalex.wordpress.com/21/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sarafianalex.wordpress.com/21/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sarafianalex.wordpress.com/21/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sarafianalex.wordpress.com/21/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sarafianalex.wordpress.com&blog=2367780&post=21&subd=sarafianalex&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://sarafianalex.wordpress.com/2008/04/21/typed-dataset-linq-entities/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/64f00567ef7dda3ec36dcf0e01043d11?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">sarafian</media:title>
		</media:content>

		<media:content url="http://sarafianalex.files.wordpress.com/2008/04/image-thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://sarafianalex.files.wordpress.com/2008/04/image-thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
	</channel>
</rss>