<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Simon Ince's Blog : Entity Framework</title><link>http://blogs.msdn.com/simonince/archive/tags/Entity+Framework/default.aspx</link><description>Tags: Entity Framework</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Using ASP.NET Dynamic Data in an existing Web Site</title><link>http://blogs.msdn.com/simonince/archive/2009/05/01/using-asp-net-dynamic-data-in-an-existing-web-site.aspx</link><pubDate>Fri, 01 May 2009 15:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9582308</guid><dc:creator>simonince</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/simonince/comments/9582308.aspx</comments><wfw:commentRss>http://blogs.msdn.com/simonince/commentrss.aspx?PostID=9582308</wfw:commentRss><description>&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;One of the tasks I used to hate when building a new system was adding admin pages to allow simple create/update functionality for lookup data. For example, maintaining a simple list of Products. It takes ages to write, and is very boring – even if you write templates to generate code it consumes a lot of time for such a commonly repeated and simple task.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;A href="http://www.asp.net/dynamicdata"&gt;&lt;FONT size=3 face=Calibri&gt;ASP.NET Dynamic Data&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; has now arrived, which gives a great way to “scaffold” CRUD pages over an Entity Framework Object Context (or other sources). But what if I have a web site that is mostly a line-of-business system, with complex business logic and custom UI, and I need to administer a small set of tables too?&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Well, you can add Dynamic Data to a portion of your existing web site! This means you no longer need to write your own administration pages.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-SIZE: 9pt"&gt;&lt;FONT face=Calibri&gt;* &lt;I style="mso-bidi-font-style: normal"&gt;Before you start off on this merry path, &lt;A href="http://msdn.microsoft.com/en-us/library/cc668215.aspx"&gt;read this&lt;/A&gt; to make sure the relevant sections of your Entity Framework model are supported by Dynamic Data... for example, Complex Types are not.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/I&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;How?&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;There’s a walkthrough that covers adding Dynamic Data to an existing web site &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc837197.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;here&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;, so give that a read and you’ll be 80% of the way there. [&lt;B style="mso-bidi-font-weight: normal"&gt;Note&lt;/B&gt;: I also had to add a reference to System.Web.Entity at the end of the walkthrough to get it all working]&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Next, make sure you have set ScaffoldAllTables to false – the last thing you want to do is expose your non-lookup data for direct editing by admin staff. All that should be exposed is a few key tables of static data. So, in Global.asax, make sure your data model registration looks like this;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 0pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;model.RegisterContext(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 0pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;typeof&lt;/SPAN&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;OrderDbEntities&lt;/SPAN&gt;), &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 0pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;new&lt;/SPAN&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ContextConfiguration&lt;/SPAN&gt;() &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 0pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{ ScaffoldAllTables = &lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt; });&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;But how does the user get to this administration functionality? I’d recommend putting it under a virtual subfolder in your web site – perhaps named “Admin”. This is really just a route (read up on the new &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc668201.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;ASP.NET Routing&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; features if this is unfamiliar) and needn’t really exist as a physical folder. So in Global.asax, we set it up as follows;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;routes.Add(&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;DynamicDataRoute&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"Admin/{table}/{action}.aspx"&lt;/SPAN&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Constraints = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;RouteValueDictionary&lt;/SPAN&gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; { action = &lt;SPAN style="COLOR: #a31515"&gt;"List|Details|Edit|Insert"&lt;/SPAN&gt; }),&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Model = model&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;});&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Note that my route begins with “Admin/...”, which means the user will browse to URLs as follows to get to the admin pages;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;A href="http://%7badd%20address%20here%7d/myfakewebsite/Admin/Product/List.aspx"&gt;&lt;FONT color=#0000ff size=3 face=Calibri&gt;http://{add address here}/myfakewebsite/Admin/Product/List.aspx&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;You can of course link to these pages from elsewhere within your site to save the user typing them in.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;At the moment, we’re not scaffolding any of our tables, so none of these URLs will work yet. The next step, then, is to pick a table to expose for administration. I’m going to use a Product table that has ID, Description, Price and CreatedBy/CreatedDate fields. In my EF model the entity also has an OrderItems navigation property which allows me to get all Order Item records that are an instance of an order for the current product...&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;IMG style="WIDTH: 411px; HEIGHT: 338px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9582305/original.aspx" width=411 height=338 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9582305/original.aspx"&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-ALIGN: center; MARGIN: 0cm 0cm 10pt" class=MsoNormal align=center&gt;&lt;SPAN style="mso-fareast-language: EN-GB; mso-no-proof: yes"&gt;&lt;?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /&gt;&lt;v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"&gt;&lt;v:stroke joinstyle="miter"&gt;&lt;/v:stroke&gt;&lt;v:formulas&gt;&lt;v:f eqn="if lineDrawn pixelLineWidth 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 1 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum 0 0 @1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @2 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 0 1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @6 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @8 21600 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @10 21600 0"&gt;&lt;/v:f&gt;&lt;/v:formulas&gt;&lt;v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"&gt;&lt;/v:path&gt;&lt;o:lock aspectratio="t" v:ext="edit"&gt;&lt;/o:lock&gt;&lt;/v:shapetype&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Due to the way EF supports partial classes, I can tell the Dynamic Data runtime to scaffold the Product table using an attribute (from the System.ComponentModel.DataAnnotations namespace &amp;amp; assembly) on a partial class. I added a C# class to the Web Site with the same namespace as the Entity Framework model, and pasted in the following code;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;ScaffoldTable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;partial&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Immediately this attribute is added the Product table is available for editing. There are a few problems when I browse to the new page though;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;1.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;It is displaying the link to Order Items even though it isn’t editable (because Order Item isn’t scaffolded).&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 10pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;2.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;I can edit the columns I’m using for Audit – CreatedBy and CreatedDate. Not good.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;It turns out changing this is quite easy. Using some additional attributes and a metadata class as follows customises the model sufficiently (see &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc488557.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;here&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; for more info on this metadata class approach);&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;MetadataType&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;ProductMetadata&lt;/SPAN&gt;))]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;DisplayColumn&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"Description"&lt;/SPAN&gt;)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;ScaffoldTable&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;partial&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ProductMetadata&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;UIHint&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"TextReadOnly"&lt;/SPAN&gt;)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; CreatedBy;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;UIHint&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"TextReadOnly"&lt;/SPAN&gt;)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; CreatedDate;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;ScaffoldColumn&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;)]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;EntityCollection&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;OrderItem&lt;/SPAN&gt;&amp;gt; OrderItem;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I’ve now instructed the runtime not to display the Order Item navigation property, and to use the Description field should I display Products in a list somewhere (as part of a foreign key drop-down, for example).&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I’ve also asked it to use the “TextReadOnly” user control to render my CreatedDate and CreatedBy fields instead of the standard Text control, by placing a [UIHint] attribute on two metadata properties. To create the TextReadOnly control I copied-and-pasted the “Text.ascx” control twice, and renamed the copies to “TextReadOnly.ascx” and “TextReadOnly_Edit.ascx”. This control will now be used whenever the CreatedDate and CreatedBy fields are displayed (note I’ve cheated here – CreatedDate is really a date but as I’m happy with the default ToString display mechanism for it I didn’t bother creating a DateTime ReadOnly control).&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;IMG style="WIDTH: 221px; HEIGHT: 356px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9582306/original.aspx" width=221 height=356 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9582306/original.aspx"&gt;&lt;/P&gt;
&lt;P style="TEXT-ALIGN: center; MARGIN: 0cm 0cm 10pt" class=MsoNormal align=center&gt;&lt;SPAN style="mso-fareast-language: EN-GB; mso-no-proof: yes"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;As you can see, these user controls are available for you to edit under the DynamicData/FieldTemplates folder that was copied in as part of the original walkthrough. If you want to change this folder to be somewhere else, check out &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc837200.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;this article&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Finally, we probably want to limit access to the admin pages to a limited set of privileged users. The easiest way to do this is using standard ASP.NET authorisation, by adding a location and authorisation element to web.config;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;location&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: red; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;path&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;=&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;"&lt;SPAN style="COLOR: blue"&gt;Admin&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;system.web&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;authorization&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;allow&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: red; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;roles&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;=&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;"&lt;SPAN style="COLOR: blue"&gt;domain\role&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;deny&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: red; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;users&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;=&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;"&lt;SPAN style="COLOR: blue"&gt;*&lt;/SPAN&gt;"&lt;SPAN style="COLOR: blue"&gt;/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;authorization&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;system.web&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; COLOR: #a31515; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;location&lt;/SPAN&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Next steps...&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;There’s plenty more you might like to do, so I would recommend looking further into the features that Dynamic Data provides. &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;One that is particularly likely to be of interest is customising validation of data that is maintained... a good starting point is the &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute.aspx"&gt;&lt;FONT color=#0000ff size=3 face=Calibri&gt;ValidationAttribute&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;You probably also want to change Site.master to better reflect your site (or move it, rename it, and update the templates under DynamicData/PageTemplates to use the new one). As long as you have a ScriptManager and the required Content Placeholder on there, it should work great. You can obviously make use of your own CSS too, or even go as far as changing all the field templates.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;If you’d like a general overview of how Dynamic Data fits together, have a read of the &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc668159.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;Infrastructure Overview&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Finally, remember that I’m basing mine on an Entity Framework model, so I could customise the model too – for example, hooking up to the SavingChanges event to perform processing and/or validation on the Product table before it is saved to the database.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I hope all that is useful, and saves you time and boredom for your next system... enjoy!&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9582308" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/simonince/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Architecture/default.aspx">Architecture</category><category domain="http://blogs.msdn.com/simonince/archive/tags/MSArchitectPortal/default.aspx">MSArchitectPortal</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item><item><title>Auditing Data Changes in the Entity Framework: Part 2</title><link>http://blogs.msdn.com/simonince/archive/2009/04/20/auditing-data-changes-in-the-entity-framework-part-2.aspx</link><pubDate>Mon, 20 Apr 2009 17:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9556709</guid><dc:creator>simonince</dc:creator><slash:comments>15</slash:comments><comments>http://blogs.msdn.com/simonince/comments/9556709.aspx</comments><wfw:commentRss>http://blogs.msdn.com/simonince/commentrss.aspx?PostID=9556709</wfw:commentRss><description>&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;In my &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/simonince/archive/2009/04/17/auditing-data-changes-in-the-entity-framework-part-1.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;previous post&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; I described the basic concept behind my auditing approach using the Entity Framework, and covered some of the problems I encountered. This post focuses on the solution I went with; do feel free to comment if you have any thoughts.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Audit Lifecycle&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To get to the root of my requirements I wrote down the lifecycle of a piece of data, and what needed to be tracked against it.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV align=center&gt;
&lt;TABLE style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; WIDTH: 10cm; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none; mso-border-alt: solid #4F81BD 1.0pt; mso-border-themecolor: accent1; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt" class=LightList-Accent11 border=1 cellSpacing=0 cellPadding=0 width=378 class="LightList-Accent11"&gt;
&lt;TBODY&gt;
&lt;TR style="mso-yfti-irow: -1; mso-yfti-firstrow: yes"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #4f81bd; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-top-themecolor: accent1; mso-border-left-themecolor: accent1; mso-background-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 5" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: white; mso-themecolor: background1"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Action&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #4f81bd; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-top-themecolor: accent1; mso-background-themecolor: accent1; mso-border-right-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 1" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: white; mso-themecolor: background1"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Audit Requirements&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 0"&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 68" class=MsoNormal&gt;&lt;B&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Record Added&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The date it was created, by whom, and what the original values are.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 1"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-left-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 4" class=MsoNormal&gt;&lt;B&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Record Modified&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 4" class=MsoNormal&gt;&lt;I style="mso-bidi-font-style: normal"&gt;&lt;SPAN style="FONT-SIZE: 9pt; mso-bidi-font-weight: bold"&gt;&lt;FONT face=Calibri&gt;* repeated many times&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-right-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The date it was changed, by whom, and which values were changed.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 2; mso-yfti-lastrow: yes"&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 68" class=MsoNormal&gt;&lt;B&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Record Deleted&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The date it was deleted, and by whom.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The problem is that creating an audit record is tricky based on point (2) in my previous post. Therefore, I chose to record the &lt;I style="mso-bidi-font-style: normal"&gt;original values&lt;/I&gt; when each change is made. This means I actually track the following;&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV align=center&gt;
&lt;TABLE style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; WIDTH: 10cm; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none; mso-border-alt: solid #4F81BD 1.0pt; mso-border-themecolor: accent1; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt" class=LightList-Accent11 border=1 cellSpacing=0 cellPadding=0 width=378 class="LightList-Accent11"&gt;
&lt;TBODY&gt;
&lt;TR style="mso-yfti-irow: -1; mso-yfti-firstrow: yes"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #4f81bd; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-top-themecolor: accent1; mso-border-left-themecolor: accent1; mso-background-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 5" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: white; mso-themecolor: background1"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Action&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #4f81bd; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-top-themecolor: accent1; mso-background-themecolor: accent1; mso-border-right-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 1" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: white; mso-themecolor: background1"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Audit Requirements&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 0"&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 68" class=MsoNormal&gt;&lt;B&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Record Added&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The date it was created, and by whom.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 1"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-left-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 4" class=MsoNormal&gt;&lt;B&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Record Modified&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 4" class=MsoNormal&gt;&lt;I style="mso-bidi-font-style: normal"&gt;&lt;SPAN style="FONT-SIZE: 9pt; mso-bidi-font-weight: bold"&gt;&lt;FONT face=Calibri&gt;* repeated many times&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-right-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The date it was changed, by who, and what the pre-change values were.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 2; mso-yfti-lastrow: yes"&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #4f81bd 1pt solid; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 68" class=MsoNormal&gt;&lt;B&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Record Deleted&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #4f81bd 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0cm; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 231.05pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #4f81bd 1pt solid; BORDER-RIGHT: #4f81bd 1pt solid; PADDING-TOP: 0cm; mso-border-themecolor: accent1" vAlign=top width=308&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The date it was deleted, by who, and what the pre-delete values were.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;This has effectively flipped the approach on its head, but I can still get a point-in-time view of the data whenever I need it. Therefore my data model becomes something like this;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-ALIGN: center; MARGIN: 12pt 0cm 10pt" class=MsoNormal align=center&gt;&lt;SPAN style="mso-fareast-language: EN-GB; mso-no-proof: yes"&gt;&lt;?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /&gt;&lt;v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"&gt;&lt;v:stroke joinstyle="miter"&gt;&lt;/v:stroke&gt;&lt;v:formulas&gt;&lt;v:f eqn="if lineDrawn pixelLineWidth 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 1 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum 0 0 @1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @2 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 0 1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @6 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @8 21600 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @10 21600 0"&gt;&lt;/v:f&gt;&lt;/v:formulas&gt;&lt;v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"&gt;&lt;/v:path&gt;&lt;o:lock aspectratio="t" v:ext="edit"&gt;&lt;/o:lock&gt;&lt;/v:shapetype&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;IMG style="WIDTH: 351px; HEIGHT: 281px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9556708/original.aspx" width=351 height=281 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9556708/original.aspx"&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;When a new Product is added, the CreatedBy and CreatedDate fields are recorded on the Product entity. When changes are made, the &lt;I style="mso-bidi-font-style: normal"&gt;previous&lt;/I&gt; unchanged version of the entity is copied to the ProductHistory table, and then the new Product entity is saved. When a Product is deleted, it is removed from the Product table and a copy of its last values is saved to ProductHistory.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;This means my ChangedDate field on ProductHistory could arguably be described better as “ExpiredDate”, as it is the date and time that the data on that record became out of date. &lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Enabling Auditing on the ObjectContext&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I described in my previous post how I would use the SavingChanges event to create audit records. To wire this up, I’ve created an extension method that can be called on an ObjectContext;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;void&lt;/SPAN&gt; Audit&amp;lt;fromType, toType&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ObjectContext&lt;/SPAN&gt; context, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Func&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;IDataRecord&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;EntityState&lt;/SPAN&gt;, toType&amp;gt; mapping, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Action&lt;/SPAN&gt;&amp;lt;toType&amp;gt; addToContext)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;context.SavingChanges += &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;EventHandler&lt;/SPAN&gt;((o, e) =&amp;gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;CreateAuditRecord&amp;lt;fromType, toType&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;context, mapping, addToContext));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Calling this method sets up auditing for one specific type of entity by adding an event handler to the SavingChanges event. The handler invokes a method called CreateAuditRecord.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;You might think it would be better to set all audit types up at once, or you might want to configure auditing in the ObjectContext’s OnContextCreated partial method... and that should be easy enough. The point of this code is not to be final, but that it should be easy for you to understand and adapt.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;So why have I used two type parameters, a Func&amp;lt;T,U,V&amp;gt; and an Action&amp;lt;T&amp;gt; on the Audit method then? It comes down to points (4) and (5) in my previous post; I wanted auditing to be very explicit about how it behaved, and I wanted to avoid passing string values around to identify field names or entity sets.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To demonstrate this, consider the following example of how I would enable auditing on the Product entity, saving changes to ProductHistory. &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;using&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: #2b91af"&gt;MyEntities&lt;/SPAN&gt; db = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;MyEntities&lt;/SPAN&gt;())&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;db.Audit&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;ProductHistory&lt;/SPAN&gt;&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;(record, action) =&amp;gt; &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ProductHistory&lt;/SPAN&gt;() { &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Id = record.Field&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;&amp;gt;(f =&amp;gt; f.Id), &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Description = record.Field&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;f =&amp;gt; f.Description), &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Price = record.Field&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt;&amp;gt;(f =&amp;gt; f.Price),&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;CreatedDate = record.Field&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;DateTime&lt;/SPAN&gt;&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;f =&amp;gt; f.CreatedDate),&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;CreatedBy = record.Field&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;f =&amp;gt; f.CreatedBy),&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ChangedBy = &lt;SPAN style="COLOR: #a31515"&gt;"Simon"&lt;/SPAN&gt;, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ChangedDate = &lt;SPAN style="COLOR: #2b91af"&gt;DateTime&lt;/SPAN&gt;.Now, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ChangeType = action.ToString() },&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;(ph) =&amp;gt; db.AddToProductHistory(ph));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// TODO: make some changes to Product here...&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;db.SaveChanges();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;In my Audit method I specify the source entity (Product) and target audit store entity (ProductHistory) as type parameters. This then enables me to easily create a strongly typed lambda for the first parameter that I know accepts an IDataRecord (“record”) and an EntityState (“action”), returning a ProductHistory record;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;(record, action) =&amp;gt; &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ProductHistory&lt;/SPAN&gt;() { &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Id = record.Field&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Product&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;&amp;gt;(f =&amp;gt; f.Id), ... &amp;lt;snip&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The purpose of this method is to map a Product data record to a ProductHistory entity. It has an IDataRecord input as I pass the &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectstateentry.originalvalues.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;OriginalValues&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; to it, not the full Product entity (remember I’m saving the previous values in my audit table, not the new ones). Therefore this code creates a ProductHistory record, and initialises its properties using &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/bb384062.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;object initialiser&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; syntax. If this code became too unwieldy I could easily factor it out into a helper method.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Next, you’ll notice that I’m using another extension method named “Field” that applies to the IDataRecord type. I use this to fetch a property value in a strongly typed way, and to make it easy to get at fields that represent an entity property. &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;In this case, I’m specifying that I expect the IDataRecord to contain fields that represent Product’s members. I’m also saying the particular property I’m after is an integer, and then I use a lambda to identify the property itself (Id in this case).&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The second parameter to my Audit call looks like this;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;(ph) =&amp;gt; db.AddToProductHistory(ph)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;This is because I need to know how to add audit records that are created to the ObjectContext, ensuring they are saved as part of the same SaveChanges transaction as the actual changes we’re tracking. The lambda receives a ProductHistory entity (which is known because of the “toType” type parameter in my call to Audit) which I choose to add to the ObjectContext by calling AddToProductHistory.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;For this task I could have used the more general AddObject method available on an ObjectContext – but this needs a string value to identify the entity set, and I want as much compile time checking as possible.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;The Mechanics of Auditing&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Now you see how we setup auditing, let’s dive into the CreateAuditRecord method to see how it actually creates the audit trail. &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;First, the method retrieves a list of ObjectStateEntry objects that describe entities that have either been modified or deleted. Remember that my approach doesn’t record anything in the audit table when they are added;&lt;/FONT&gt;&lt;/P&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #2b91af; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: #2b91af; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;IEnumerable&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;FONT color=#000000&gt;&amp;lt;&lt;/FONT&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ObjectStateEntry&lt;/SPAN&gt;&lt;FONT color=#000000&gt;&amp;gt; entities = &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt;&lt;FONT color=#000000&gt; e &lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt;&lt;FONT color=#000000&gt; context.ObjectStateManager.GetObjectStateEntries(&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;EntityState&lt;/SPAN&gt;&lt;FONT color=#000000&gt;.Modified | &lt;/FONT&gt;&lt;SPAN style="COLOR: #2b91af"&gt;EntityState&lt;/SPAN&gt;&lt;FONT color=#000000&gt;.Deleted)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;where&lt;/SPAN&gt;&lt;FONT color=#000000&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;FONT color=#000000&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;e.IsRelationship == &lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt;false&lt;/SPAN&gt;&lt;FONT color=#000000&gt; &amp;amp;&amp;amp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;FONT color=#000000&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;&lt;FONT color=#000000&gt;(fromType).IsAssignableFrom(e.Entity.GetType())&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt;&lt;FONT color=#000000&gt; e;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="mso-no-proof: yes"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;This also ensures that we only get results for entity types that are of type “fromType”, or inherit from it. Arguably this would be more efficient if it looped through all changes looking for the audit configuration for each type as it went... or there may be other desired behaviours for inheritance heirarchies – but that is out of scope for this post, and it should be easy for you to see how you might change it.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 12pt 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="mso-no-proof: yes"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Next, we loop through all of our results;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;foreach&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; (&lt;SPAN style="COLOR: #2b91af"&gt;ObjectStateEntry&lt;/SPAN&gt; item &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; entities)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;toType auditRecord = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;mapping(item.OriginalValues, item.State);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;addToContext(auditRecord);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;... and it is just a case of using the supplied helper functions to map the OriginalValues IDataRecord to a ProductHistory (in this example), and then add it to the ObjectContext. Of course these helper functions are in the form of the lambdas we passed to our call to the Audit extension method.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Retrieving Point-in-Time Products&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;This design is based on the assumption that I will rarely need to retrieve audited data, as it requires some calculations and slightly complex SQL to complete. This is fine, but if you were retrieving audit data very frequently I would consider doing some further testing, with a view to optimising the approach.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;So how do I get a Product record as it looked at 3pm on the 20&lt;SUP&gt;th&lt;/SUP&gt; April 2009, for example?&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Simply put, to get the correct data fields for a given time I need to find the first ProductHistory record &lt;U&gt;after&lt;/U&gt; the specified date &amp;amp; time. If there are none, I need the values on the Product record (as this means no changes had been made to the record at that point in time). Let’s break that down.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;First I need to get the first record from ProductHistory for products that were created before the specified date &amp;amp; time, but were changed after it...&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;SELECT&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Id&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; [Description]&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; Price&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; CreatedBy&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; CreatedDate&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;FROM&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: gray; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;SELECT&lt;/SPAN&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Id&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; [Description]&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; Price&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; CreatedBy&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; CreatedDate&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: fuchsia"&gt;ROW_NUMBER&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;()&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;OVER&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;ORDER&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;BY&lt;/SPAN&gt; ChangedDate&lt;SPAN style="COLOR: gray"&gt;)&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;AS&lt;/SPAN&gt; DateOrder &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;FROM&lt;/SPAN&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ProductHistory&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;WHERE&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;CreatedDate &lt;SPAN style="COLOR: gray"&gt;&amp;lt;=&lt;/SPAN&gt; @PointInTime&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;AND&lt;/SPAN&gt; ChangedDate &lt;SPAN style="COLOR: gray"&gt;&amp;gt;&lt;/SPAN&gt; @PointInTime&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;AND&lt;/SPAN&gt; Id &lt;SPAN style="COLOR: gray"&gt;=&lt;/SPAN&gt; @Id&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;)&lt;/SPAN&gt; A&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;WHERE&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;A&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;DateOrder &lt;SPAN style="COLOR: gray"&gt;=&lt;/SPAN&gt; 1&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Next, I need all Products that have no ProductHistory records that fall into the above category, but were created before the specified date &amp;amp; time;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;SELECT&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Id&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; [Description]&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; Price&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; CreatedBy&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; CreatedDate&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;FROM&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Product&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;WHERE&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;NOT&lt;/SPAN&gt; &lt;SPAN style="COLOR: gray"&gt;EXISTS&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;SELECT&lt;/SPAN&gt; &lt;SPAN style="COLOR: gray"&gt;*&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;FROM&lt;/SPAN&gt; ProductHistory ph &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;WHERE&lt;/SPAN&gt; ph&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;Id &lt;SPAN style="COLOR: gray"&gt;=&lt;/SPAN&gt; Product&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;Id &lt;SPAN style="COLOR: gray"&gt;AND&lt;/SPAN&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 3"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;CreatedDate &lt;SPAN style="COLOR: gray"&gt;&amp;lt;=&lt;/SPAN&gt; @PointInTime &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 3"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;AND&lt;/SPAN&gt; ChangedDate &lt;SPAN style="COLOR: gray"&gt;&amp;gt;&lt;/SPAN&gt; @PointInTime&lt;SPAN style="COLOR: gray"&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;AND&lt;/SPAN&gt; CreatedDate &lt;SPAN style="COLOR: gray"&gt;&amp;lt;=&lt;/SPAN&gt; @PointInTime&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;AND&lt;/SPAN&gt; Id &lt;SPAN style="COLOR: gray"&gt;=&lt;/SPAN&gt; @Id&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Put these two query sections together using a UNION statement and we have the content of my [GetPointInTimeProduct] Stored Procedure (see the code download), which allows us to find the exact state of a Product given its identifier and a specific date and time. I’ve brought it into my model using a &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc716672.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;Function Import&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;The Good and the Bad&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I hope all that has made sense – as usual I’ve included the code as a download (standard &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/simonince/about.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;disclaimers&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; apply). There are of course some pros and cons to my approach – some that spring to mind are below. If you have comments on better ways to do this, or thoughts about my approach, feel free to chip in!&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;We can easily record the username of whoever made the changes as we can deduce it in our C# code; even in a trusted subsystem model.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;The approach is easy to configure in a compile-time checked fashion. It doesn’t rely on possibly flawed convention (e.g. always store audit records in tables ending “Audit”). It should also therefore be easy to refactor to suit your needs.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;Mappings between entity and audit records are explicit, so it does not dictate too much about how you would do this. You could store completely different audit data to me if you’d like.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;The audit records participate in the ObjectContext’s Unit of Work; that is, they are saved in a batch of SQL statements with the data changes. It also means that due to the ordering and batching of updates that the likelihood of locks and deadlocks is arguably reduced when compared to some other approaches.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;The configuration of auditing for each type independently keeps the code clear, but introduces some inefficiency (such as many subscribers to the SavingChanges event, and many loops through the ObjectStateEntry collection).&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;The data model, although simple, needs explanation. The history records may not work quite how a newcomer would assume.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;The complexity of the point-in-time SQL is slightly higher than I would like.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;[&lt;B style="mso-bidi-font-weight: normal"&gt;Edit&lt;/B&gt;] It is important to use some kind of concurrency checking to ensure that multiple audit records are not written by different users... I tend to use a timestamp with “Fixed” concurrency.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 10pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;[&lt;B style="mso-bidi-font-weight: normal"&gt;Edit&lt;/B&gt;] The biggest drawback of the code so far is that it doesn’t record changes to relationships... so it is suited well to resource data tables, but not so well to those involved in a complex model. &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;On balance, overall I like the approach. What do you think?&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-SIZE: 9pt"&gt;Note&lt;/SPAN&gt;&lt;/B&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-SIZE: 9pt"&gt;:&lt;I style="mso-bidi-font-style: normal"&gt; Regarding the edits, I just reread this and realised I’d oversimplified for this post and missed two important points from my notes... that’ll teach me to type up blog posts late at night! Sorry.&lt;o:p&gt;&lt;/o:p&gt;&lt;/I&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9556709" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/simonince/attachment/9556709.ashx" length="11403" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/simonince/archive/tags/Architecture/default.aspx">Architecture</category><category domain="http://blogs.msdn.com/simonince/archive/tags/MSArchitectPortal/default.aspx">MSArchitectPortal</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item><item><title>Auditing Data Changes in the Entity Framework: Part 1</title><link>http://blogs.msdn.com/simonince/archive/2009/04/17/auditing-data-changes-in-the-entity-framework-part-1.aspx</link><pubDate>Fri, 17 Apr 2009 16:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9554242</guid><dc:creator>simonince</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/simonince/comments/9554242.aspx</comments><wfw:commentRss>http://blogs.msdn.com/simonince/commentrss.aspx?PostID=9554242</wfw:commentRss><description>&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;If you’ve read my last post on &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/simonince/archive/2009/04/16/types-of-auditing.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;Types of Auditing&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;, you should be primed for this one; I’m looking at a way to do Data Operation Auditing in the Entity Framework. That is, I want to track &lt;B style="mso-bidi-font-weight: normal"&gt;who&lt;/B&gt; changes &lt;B style="mso-bidi-font-weight: normal"&gt;which tables &amp;amp; columns&lt;/B&gt;, &lt;B style="mso-bidi-font-weight: normal"&gt;when&lt;/B&gt;, and in &lt;B style="mso-bidi-font-weight: normal"&gt;what way&lt;/B&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Why does this specifically apply to the Entity Framework? Well there are three main reasons;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;1.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;A lot of DBAs don’t like triggers in their database. In fact, I don’t like triggers in my database! I find them to be more difficult to manage, and often overlooked during defect investigation. I also don’t like the cascading updates that can occur as a result of triggers.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;2.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;In a &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/aa480587.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;Trusted Subsystem&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; model, which is often my preferred security configuration, the database is accessed as a service account. This means that triggers and SQL statements have no automatic concept of &lt;B style="mso-bidi-font-weight: normal"&gt;who&lt;/B&gt; is performing the data changes, as the user’s security context has not been delegated through to the data tier.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 10pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;3.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;People are starting to use the Entity Framework, so I’m keen to maximise the benefits of using it. It also places some constraints on an auditing approach – for example, out of the box, the Entity Framework cannot pass values that are not contained in an entity to the database during DML operations... so username, for example, can’t be passed down to a Stored Procedure when saving entity changes.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;In this post I’ll cover the basic solution concept I’ve used, and some of the problems I encountered. In the next post I’ll detail my final solution. This isn’t some poor attempt at leaving a post on a cliff-hanger to keep you coming back – I just want to keep each post short enough to digest easily!&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Basic Design&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The Entity Framework extensibility point that seems to fit my requirements best is the &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.savingchanges.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;SavingChanges&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; event on an ObjectContext. This fires when changes are &lt;I style="mso-bidi-font-style: normal"&gt;just about &lt;/I&gt;to be saved (i.e. before the SQL is actually generated). Therefore this is a great opportunity for us to check what has been changed, and generate our audit records. I can even add more entities (containing audit information) at this point to the ObjectContext and they’ll get saved too.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To find what has changed we can use &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectstatemanager.getobjectstateentries.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;ObjectStateManager.GetObjectStateEntries&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; – this is accessible via the &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;ObjectContext&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;’s ObjectStateManager property, and gives us access to information about the original and current values of each property on an entity, whether it has been Added, Modified, or Deleted, and some other useful metadata.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To store data audit records I created a copy of the table I’m auditing, and added some metadata fields. For example, if I have a Product table, I would add a ProductHistory table – something like the following;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;IMG style="WIDTH: 258px; HEIGHT: 167px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9554237/original.aspx" width=258 height=167 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9554237/original.aspx"&gt;&lt;/P&gt;
&lt;P style="TEXT-ALIGN: center; MARGIN: 0cm 0cm 10pt" class=MsoNormal align=center&gt;&lt;SPAN style="mso-fareast-language: EN-GB; mso-no-proof: yes"&gt;&lt;?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /&gt;&lt;v:shapetype id=_x0000_t75 coordsize="21600,21600" o:spt="75" o:preferrelative="t" path=" m@4@5 l@4@11@9@11@9@5 xe" filled="f" stroked="f"&gt;&lt;v:stroke joinstyle="miter"&gt;&lt;/v:stroke&gt;&lt;v:formulas&gt;&lt;v:f eqn="if lineDrawn pixelLineWidth 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 1 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum 0 0 @1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @2 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 0 1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @6 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @8 21600 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @10 21600 0"&gt;&lt;/v:f&gt;&lt;/v:formulas&gt;&lt;v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"&gt;&lt;/v:path&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:lock v:ext="edit" aspectratio="t"&gt;&lt;/o:lock&gt;&lt;/v:shapetype&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Note that the Primary Key in Product is the Id field – but in ProductHistory a basic counter field is the Primary Key (AuditId), and Id is a reference to the Id field in the Product table. This is because we’re expecting multiple history records per product. &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I’ve also added metadata about who changed the record, when, and in what way (i.e. Modified, Deleted, etc).&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;None of this is particularly surprising – it is a pretty standard way to record audit information, in the form of data “deltas”.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Gotchas&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I did try a number of different approaches before I settled on one, and this was due to some interesting gotchas...&lt;/FONT&gt;&lt;/P&gt;
&lt;H3 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=3 face=Cambria&gt;1: Don’t Create a Foreign Key&lt;/FONT&gt;&lt;/H3&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;You may have noticed there’s no relationship in my data model. That’s intentional; if I delete a Product, I still want to keep my ProductHistory records for that Product, and that means I can’t have ProductHistory.Id related to Product.Id – as referential integrity would break.&lt;/FONT&gt;&lt;/P&gt;
&lt;H3 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=3 face=Cambria&gt;2: Can’t Save Added Records&lt;/FONT&gt;&lt;/H3&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;The SavingChanges event fires &lt;U&gt;before&lt;/U&gt; changes are saved to the database. In my data model I’m using database-generated keys (i.e. IDENTITY(1,1) fields). This means only after the changes have been saved to the database is the value of the key available in our in-memory representation of the database – our ObjectContext.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;This means that if we detect an entity has been added to the ObjectContext, I might want to add a record to the history table... but I cannot get the value to put in the Id field, because it hasn’t been created yet. To get around this, I could allow SaveChanges to complete, and then create my audit records, and call SaveChanges again... but that feels like a hack and would lead to other compromises, so I avoided it.&lt;/FONT&gt;&lt;/P&gt;
&lt;H3 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=3 face=Cambria&gt;3: Don’t Create a Conceptual Association&lt;/FONT&gt;&lt;/H3&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To get around point (2), I thought I had a solution. The Entity Framework automatically manages this key-relationship problem for us using &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/bb399562.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;navigation properties&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;. If I just add an association in my CSDL linking Product and ProductHistory, this would mean ProductHistory records would be inserted &lt;I style="mso-bidi-font-style: normal"&gt;after&lt;/I&gt; Product records, and the framework will fix up the Id values for me.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;But of course, as soon as we come to deleting records we come across the same issue as point (1), but within the ObjectContext rather than the database – it will not permit us to add a ProductHistory record with an Id that refers to a Product record that we’re about to delete in the same transaction. In fact, a bit of hacking and I managed to create some pretty serious bugs in my code trying to work around this!&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;There are possibly some solutions here that involve Conditional Mappings, QueryViews, DefiningQuery, database-level updateable Views, or more. But each one felt wrong to me – they had maintenance implications, could create quite brittle code, would be overwritten when using the “update from database” menu option, or worse. If you have a good solution, let me know – but I avoided them.&lt;/FONT&gt;&lt;/P&gt;
&lt;H3 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=3 face=Cambria&gt;4: Avoid Passing Strings Around&lt;/FONT&gt;&lt;/H3&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;One of the things I love about the Entity Framework is that a lot of code becomes strongly typed, and is therefore checked at compile time. In a few places this isn’t necessarily the case – such as accessing &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.data.common.dbdatarecord.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;DbDataRecord&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; field values, or calling &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.addobject.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;ObjectContext.AddObject&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To address this I took a tip from Stuart Leeks – check out &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/stuartleeks/archive/2008/08/27/improving-objectquery-t-include.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;this great post&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; on how lambda expressions can be used to bring compile-time checking to your application. I added similar code to my solution to address slightly different areas.&lt;/FONT&gt;&lt;/P&gt;
&lt;H3 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=3 face=Cambria&gt;5: Avoid Auditing by Convention&lt;/FONT&gt;&lt;/H3&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Convention over configuration can be a valid approach in some circumstances. For a general blog post and flexible solution, though, it felt wrong – I wanted to explicitly select which entities are audited to which tables, through compile-time checked, strongly typed, clear code.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;You might not like my approach to this – but I chose it to ensure it was clear what I was doing. Therefore it’s easy for you to put your own flavour on it if needed; I hope you agree!&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Solution&lt;/FONT&gt;&lt;/H2&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Calibri','sans-serif'; FONT-SIZE: 11pt; mso-ascii-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-GB; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"&gt;So how did I implement it in the end? Watch this space and I’ll post my code shortly.&lt;/SPAN&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9554242" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/simonince/archive/tags/Architecture/default.aspx">Architecture</category><category domain="http://blogs.msdn.com/simonince/archive/tags/MSArchitectPortal/default.aspx">MSArchitectPortal</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item><item><title>Types of Auditing</title><link>http://blogs.msdn.com/simonince/archive/2009/04/16/types-of-auditing.aspx</link><pubDate>Thu, 16 Apr 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9552727</guid><dc:creator>simonince</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/simonince/comments/9552727.aspx</comments><wfw:commentRss>http://blogs.msdn.com/simonince/commentrss.aspx?PostID=9552727</wfw:commentRss><description>&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Auditing almost means something different to everyone I speak to... just a few things people mean when they say “our system has auditing” to me are;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="COLOR: #4f81bd; mso-themecolor: accent1"&gt;Business Operation Auditing&lt;/SPAN&gt;&lt;/B&gt;. This is recording when a business operation is performed, such as “Hire Employee”. They usually signify that a whole lot of work has been done across the system’s databases and services.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="COLOR: #4f81bd; mso-themecolor: accent1"&gt;Data Operation Auditing&lt;/SPAN&gt;&lt;/B&gt;. This refers to tracking individual changes to database tables. For example, this might involve recording that a user performed an operation that caused the Employee table’s row with identifier “5” to have the “Hired” flag set to “true”.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;SPAN style="COLOR: #4f81bd; mso-themecolor: accent1"&gt;System Auditing&lt;/SPAN&gt;&lt;/B&gt;. This is usually what I would call &lt;U&gt;tracing&lt;/U&gt; or &lt;U&gt;instrumentation&lt;/U&gt; rather than auditing – i.e. outputting detailed information about the running of the system. This often uses the &lt;/FONT&gt;&lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;TraceSource&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt; class, performance counters, or might be custom statistics recorded in a database/file about long running tasks – it can take many forms.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I’m sure this list is by no means complete – it isn’t intended to be. It’s just designed to make you think “what do they mean by auditing?” when you’re reading the requirements for the shiny new system you’re about to write. What is it you need to achieve? &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;I’m also hopeful that when I visit you one day in the future and say “what do you mean by auditing?”... you’ll realise I’m just trying to make sure we’re talking about the same thing &lt;/FONT&gt;&lt;SPAN style="FONT-FAMILY: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings"&gt;&lt;SPAN style="mso-char-type: symbol; mso-symbol-font-family: Wingdings"&gt;J&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;My next couple of posts will cover one approach to &lt;I style="mso-bidi-font-style: normal"&gt;Data Operation Auditing&lt;/I&gt; in the Entity Framework, so stay tuned...&lt;/FONT&gt;&lt;/P&gt;&lt;I style="mso-bidi-font-style: normal"&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Calibri','sans-serif'; FONT-SIZE: 9pt; mso-ascii-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-GB; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"&gt;* You might think there’s a rather large gap in the above... what about Security Auditing? Well, I’ve left it out deliberately as I see that as more of a vertical slice compared to the horizontal list that I’ve come up with. In other words, it’s just a slightly different way to different cut it – I’d categorise Security Auditing as either System or Business Operation auditing, depending upon your requirements, the technology you’re using for authentication and authorisation, and how you choose to implement it.&lt;/SPAN&gt;&lt;/I&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9552727" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/simonince/archive/tags/Patterns/default.aspx">Patterns</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Architecture/default.aspx">Architecture</category><category domain="http://blogs.msdn.com/simonince/archive/tags/MSArchitectPortal/default.aspx">MSArchitectPortal</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item><item><title>Mapping two Tables to one Entity in the Entity Framework</title><link>http://blogs.msdn.com/simonince/archive/2009/03/23/mapping-two-tables-to-one-entity-in-the-entity-framework.aspx</link><pubDate>Mon, 23 Mar 2009 21:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9502248</guid><dc:creator>simonince</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/simonince/comments/9502248.aspx</comments><wfw:commentRss>http://blogs.msdn.com/simonince/commentrss.aspx?PostID=9502248</wfw:commentRss><description>&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;Whilst at Q-Con a few weeks ago someone asked me about how to map two database tables to one entity in the Entity Framework... something a lot of people want to do at some point or another. At this point I must thank Chris Barker for pinging me some links to get this working. It seems a common thing to need to do so I thought I’d post briefly here.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Options&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;There are actually two main options;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 0pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;1.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;Do the mapping in the Entity Framework, which requires that both tables must share the same primary key. Therefore if you have Customer and CustomerAddress tables (with a 1:1 relationship) the CustomerId must be the primary key on the CustomerAddress table.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -18pt; MARGIN: 0cm 0cm 10pt 36pt; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;2.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3 face=Calibri&gt;Do the mapping in the database, using an updatable View that you manually map into the Entity Framework’s model. Rick has a post about how you might do this &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/rickandy/archive/2008/10/04/how-to-create-an-updateable-view-with-ado-entity-framework.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;here&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;If you want to use Option 1, which I personally prefer (assuming you have control of the database schema at this point), there is a walkthrough in the documentation &lt;/FONT&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/cc716698.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;here&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;. The walkthrough creates a new entity type – I actually cheated and made it even simpler.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;Walkthrough&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;I have two simple tables – Customer and CustomerAddress. I want them to be encapsulated in a single Customer entity within my Entity Framework model.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;IMG style="WIDTH: 225px; HEIGHT: 315px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502223/original.aspx" width=225 height=315 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502223/original.aspx"&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;FONT face=Calibri&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;When I generate my entity model this gives me two entities in both the Conceptual and Storage schemas, appropriately mapped. It looks a bit like this;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;IMG style="WIDTH: 374px; HEIGHT: 210px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502226/original.aspx" width=374 height=210 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502226/original.aspx"&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;The problem is, I want my address fields on the Customer entity. There are two ways to achieve this... the “designer” way is to right click “Line1” and choose Cut, then Paste it into the Scalar Properties in Customer, then repeat for all the remaining properties (except of course CustomerId – that’s already there). &lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;The XML fan way is to dive into the Conceptual Schema in the dbml file and add these properties manually. I find this quicker as I can copy/paste and tweak the names very easily and all in one operation (for example, if I want to call a field AddressLine1 instead). I end up with the following XML;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;A title=Zoom href="http://blogs.msdn.com/photos/simoninceblog/images/9502229/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/simoninceblog/images/9502229/original.aspx"&gt;&lt;IMG style="WIDTH: 500px; HEIGHT: 88px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502229/500x88.aspx" width=500 height=88 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502229/500x88.aspx"&gt;&lt;/A&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;This gives us a slightly different looking interim model, as CustomerAddress starts to become a bit empty;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;IMG style="WIDTH: 372px; HEIGHT: 250px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502235/original.aspx" width=372 height=250 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502235/original.aspx"&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;So now we have a nice complete Entity in our Conceptual space; next we need to map these new properties to the table in the Store. I could do this in the mapping section of the XML, or we can use the designer. The tool makes some assumptions here that actually automate mapping all the properties for you if you haven’t changed their names, so I’ll use that for simplicity.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;Right-click on the Customer entity and choose “Table Mapping”. You’ll see something like the following. We can now choose to add a Table to the mapping;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;IMG align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502238/640x168.aspx" mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502238/640x168.aspx"&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;As soon as I pick CustomerAddress, it pre-populates all the fields for me with a guess at their mapping. If you’ve renamed any properties in your entity you need to fix them up manually. Also, map the CustomerId field in the database to the Id property on the entity. The result is a mapping that looks like this;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;IMG style="WIDTH: 640px; HEIGHT: 263px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502244/640x263.aspx" width=640 height=263 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502244/640x263.aspx"&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;Finally, delete the CustomerAddress entity from the designer (which just deletes it from the Conceptual schema, not the Storage schema – which is good because we need to table still!). In deleting this entity, the navigation property named CustomerAddress that was on Customer disappears, completing the tidy-up of our model.&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;... and we’re finished! &lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0cm 0pt"&gt;&lt;FONT color=#4f81bd size=4 face=Cambria&gt;A Quick Query&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;Just to prove it, a nice simple query like this now works;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; customersAndAddresses = &lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; c &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; db.Customer&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;where&lt;/SPAN&gt; c.Name.StartsWith(&lt;SPAN style="COLOR: #a31515"&gt;"Simon"&lt;/SPAN&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;select&lt;/SPAN&gt; c;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;var&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; result = customersAndAddresses.First();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; COLOR: blue; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;string&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt; address = &lt;SPAN style="COLOR: #2b91af"&gt;String&lt;/SPAN&gt;.Format(&lt;SPAN style="COLOR: #a31515"&gt;"{0}\n{1}\n{2}&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;{3}"&lt;/SPAN&gt;, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;result.Name, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;result.Line1, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;result.Line2, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;result.PostCode);&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;Using SQL Profiler to see what’s going on shows that the Entity Framework is doing the join for us, just as we would expect;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;IMG style="WIDTH: 500px; HEIGHT: 301px" align=middle src="http://blogs.msdn.com/photos/simoninceblog/images/9502245/500x301.aspx" width=500 height=301 mce_src="http://blogs.msdn.com/photos/simoninceblog/images/9502245/500x301.aspx"&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;Good huh?&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;Hope that helps!&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="MARGIN: 0cm 0cm 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9502248" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/simonince/archive/tags/SQL/default.aspx">SQL</category><category domain="http://blogs.msdn.com/simonince/archive/tags/MSArchitectPortal/default.aspx">MSArchitectPortal</category><category domain="http://blogs.msdn.com/simonince/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item></channel></rss>