{"id":37,"date":"2009-02-18T13:35:37","date_gmt":"2009-02-18T17:35:37","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/?p=37"},"modified":"2009-02-18T13:41:58","modified_gmt":"2009-02-18T17:41:58","slug":"using-the-entity-framework-to-idatareader-adapter","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/2009\/02\/18\/using-the-entity-framework-to-idatareader-adapter\/","title":{"rendered":"Using the Entity Framework (LINQ to Entity) to IDataReader Adapter"},"content":{"rendered":"<p>In a <a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/2008\/12\/14\/entity-framework-to-idatareader-adapter\/\">recent article<\/a>, I developed a theoretical basis for an adapter that allows for the adaptation of Entity Framework (EF) entities into IDataReader-implementing form, and announced the <a href=\"http:\/\/www.codeplex.com\/L2EDataReaderAdapter\">preview availability<\/a> of this software.\u00a0<\/p>\n<p>Herein I describe with more specificity the use of the adapter generator and the resultant adapters, and announce the release of the first\u00a0<a href=\"http:\/\/www.codeplex.com\/L2EDataReaderAdapter\">production-ready version<\/a>\u00a0of the adapter generator software.<\/p>\n<p><!--more--><\/p>\n<p>To introduce the use of the IDataReaderAdapter generator, consider a\u00a0hypothetical\u00a0software package with a data-layer defined as:<\/p>\n<div style=\"border: dashed 1px black;padding: 0.5em;margin-left: 1em\"><code>public interface IDataLayer<br \/>\n\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0IDataReader GetSomeData();<br \/>\n\u00a0\u00a0 \u00a0IDataReader GetSomeOtherData(int aParameter);<br \/>\n\u00a0\u00a0 \u00a0}<\/code><\/div>\n<p>Business-process code interacts with this data logic exclusively through the IDataLayer interface; this not only creates a clean <a href=\"http:\/\/en.wikipedia.org\/wiki\/Separation_of_concerns\">separation of concerns<\/a>, but also allows for run-time specification of arbitrary IDataLayer implementation (typically a la <a href=\"http:\/\/en.wikipedia.org\/wiki\/Dependency_injection\">dependency injection<\/a>). \u00a0This might be concretely implemented as:<\/p>\n<div style=\"border: dashed 1px black;padding: 0.5em;margin-left: 1em\"><code>public class DataLayer : IDataLayer<br \/>\n\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0public IDataReader GetSomeData()<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return SqlHelper.ExecuteReader(connectionString, \"GetSomeData\");<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}<\/code><code><br \/>\n\u00a0\u00a0 \u00a0public IDataReader GetSomeOtherData(int aParameter)<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0return SqlHelper.ExecuteReader(connectionString, \"GetSomeOtherData\", aParameter);<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}<br \/>\n\u00a0\u00a0 \u00a0}<\/code><\/div>\n<p>For those developers wishing to move to Microsoft&#8217;s <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa697427(VS.80).aspx\">Entity Framework<\/a> (EF), this presents a problem. \u00a0There is no ready method by which one may convert an <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.objects.dataclasses.entityobject.aspx\">EntityObject<\/a>\u00a0into an IDataRecord (and, similarly, an IEnumerable&lt;EntityObject&gt; into IDataReader). \u00a0Without such a conversion, it is not possible to transition to the EF without breaking the IDataLayer interface contract. \u00a0For those applications that are widely deployed (or have strong third-party augmentation), this is a very real problem indeed.<\/p>\n<p>The IDataReaderAdapter generator allows for such a conversion in two ways:<\/p>\n<ol>\n<li>Compile-time adaption an EF schema into a set of IDataRecord-implementing wrappers <span style=\"text-decoration: underline\">without<\/span> the use of reflection (and of O(n) property-lookup performance), or<\/li>\n<li>Run-time adaption of an EntityObject (or any) object to an IDataRecord-implementing counterpart through the use of reflection.<\/li>\n<\/ol>\n<div>Developers are free to choose the method of adaption based upon his or her particular needs.<\/div>\n<p><strong>Note:<\/strong>\u00a0The adapter generator may be used to adapt <span style=\"text-decoration: underline\">any<\/span>\u00a0objects into IDataRecord\/Reader-implementing objects. \u00a0Though the functionality described herein largely deals with the EF, the generator may be applied against any arbitrary object.<\/p>\n<h4>Method 1: Compile-Time Adaption of an Entity Framework Schema<\/h4>\n<p>To produce IDataRecord\/Reader-implementing adapters at compile-time, we execute the adapter generator utility and point it at our EF schema. \u00a0The utility is executed in one of two ways, with syntax as:<\/p>\n<p><code>IDataReaderAdapterGenerator<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\/entities:[.NET Entity Framework EDMX file]<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\/output:[output class filename]<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0[\/entities:[entity regex]<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0[\/language:vb|c#]<\/code><\/p>\n<p><code>IDataReaderAdapterGenerator<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\/assembly:<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\/output:[output class filename]<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0[\/objects:[entity regex]<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0[\/language:vb|c#]<\/code><\/p>\n<ul>\n<li><strong>Entities\/Assembly<\/strong>: Here, the first parameter may either be an EF Entity Data Model XML (EDMX) file or an arbitrary assembly. \u00a0The adapter generator will, assuming the former, parse the EDMX, extract entity objects, and create adapters. \u00a0If an assembly is specified, adapters are generated for each publicly-exposed object in that assembly.<\/li>\n<li><strong>Output<\/strong>: This parameter specifies the output file for the generated adapters (i.e.; &#8220;Samples.cs&#8221; or &#8220;Samples.vb&#8221;).<\/li>\n<li><strong>Entities\/Objects<\/strong>: This setting specifies the particular entities or objects that are adapted. \u00a0This is specified as a regular expression (to adapt all entities or objects containing the word &#8220;Data&#8221; one would use the pattern &#8220;.*Data.*&#8221;). \u00a0By default, all available objects are adapted.<\/li>\n<li><strong>Language<\/strong>: This allows specification of the target language for the generated adapters, either VB.NET or C#.<\/li>\n<\/ul>\n<h4>Method #2: Run-time Adaption of Objects<\/h4>\n<p>As an alternative to compile-time generation of IDataRecord\/Reader-implementing objects, arbitrary objects may also be adapted at run-time. \u00a0Note, however, that this flexibility is achieved at the expense of the additional overhead required for the reflection used during access. \u00a0Consider this cost carefully &#8212; it is likely that compile-time adaption should be utilized wherever possible.<\/p>\n<h4>Utilizing IDataRecord\/Reader Adapters<\/h4>\n<p>Irrespective of the method selected above, the resultant adapters are used in much the same manner. \u00a0By way of example, consider the data model that would result when the concrete\u00a0DataLayer above were converted to utilize the EF. \u00a0This model would likely contain two entities, SomeData and SomeOtherData, and would be structured as follows:<\/p>\n<p><a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/files\/2009\/02\/sample-data-model.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-38\" src=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/files\/2009\/02\/sample-data-model-300x212.jpg\" alt=\"\" width=\"300\" height=\"212\" \/><\/a><\/p>\n<p>If this EDMX existed in a file named SampleDataModel.edmx, we would adapt the model as:<\/p>\n<p><code>IDataReaderAdapterGenerator \/entities:SampleDataModel.edmx \/output:AdaptedSample.cs<\/code><\/p>\n<p>And we would implement our modern IDataLayer-implementing layer as:<\/p>\n<div style=\"border: dashed 1px black;padding: 0.5em;margin-left: 1em\"><code>using BrandonHaynes.Data;public class ModernDataLayer : IDataLayer<br \/>\n\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0\/\/ Expose our entity model for new code to access<br \/>\n\u00a0\u00a0 \u00a0public ObjectContext EntityModel<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0{ get { return new SampleDataModel()); }\u00a0\u00a0 \u00a0public IDataReader GetSomeData()\u00a0\u00a0<\/p>\n<p>\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0using(var context = new SampleDataModel())<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0return new DataReaders.SomeDataDataReader(context.SomeData);<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}<\/p>\n<p><\/code><code>\u00a0\u00a0 \u00a0public IDataReader GetSomeOtherData(int aParameter)<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0{<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0using(var context = new SampleDataModel())<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0return new DataReaders.SomeOtherDataDataReader(context.SomeOtherData<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0.Where(someOtherData =&gt; someOtherData.id == aParameter));<br \/>\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}<br \/>\n\u00a0\u00a0 \u00a0}<\/code><\/p>\n<\/div>\n<p>Note the use of BrandonHaynes.Data.DataReaders.SomeDataDataReader and BrandonHaynes.Data.DataReaders.SomeOtherDataDataReader to adapt returned EntityObjects (context.SomeData and context.SomeOtherData.Where(&#8230;)) into IDataReader-implementing interfaces.<\/p>\n<p>To adapt objects at run-time using reflection, we would substitute these per-object adapters with the use of BrandonHaynes.Data.ReflectedDataReaderAdapter (or ReflectedDataRecordAdapter). \u00a0This would, for example, read as:<\/p>\n<p><code>\u00a0\u00a0 return new ReflectedDataReaderAdapter(context.SomeData);<\/code><\/p>\n<h4>Conclusion<\/h4>\n<p>Herein we described the command-line use of the IDataReader Adapter generation tool to produce IDataRecord and IDataReader-adapting objects. \u00a0These objects may be used to modernize provider-based data layers that heavily rely on these interfaces, without breaking the existing contract.\u00a0<\/p>\n<p>The\u00a0<a href=\"http:\/\/www.codeplex.com\/L2EDataReaderAdapter\">project site<\/a>, in addition to the source for both generators, includes two samples that should be reviewed by those interested in implementing these techniques in a production environment. \u00a0The first includes a sample model similar to that described herein, while the second includes a sample DotNetNuke data provider. \u00a0We will revisit this latter sample in subsequent entries as we explore advanced applications of the generated objects.<\/p>\n<p>This entry will be followed by an exploration in more detail of the actual generated IDataReader and IDataRecord-adapting objects, including a review of the actual generated code. \u00a0For compile-time generated objects property conversion is performed in O(n) time with the mere addition of a constant-time hash (and lazy-loaded initialization).<\/p>\n<p>As always, comments and feedback are greatly appreciated.<\/p>\n<p>B<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a recent article, I developed a theoretical basis for an adapter that allows for the adaptation of Entity Framework (EF) entities into IDataReader-implementing form, and announced the preview availability of this software.\u00a0 Herein I describe with more specificity the use of the adapter generator and the resultant adapters, and announce the release of the [&hellip;]<\/p>\n","protected":false},"author":1933,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3901,142],"tags":[3900,19472,3279,3899,19469],"class_list":["post-37","post","type-post","status-publish","format-standard","hentry","category-entity-framework-ef","category-technology","tag-entity-framework","tag-entity-framework-ef","tag-linq","tag-linq-to-entities","tag-technology"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/37","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/users\/1933"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/comments?post=37"}],"version-history":[{"count":0,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/37\/revisions"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/media?parent=37"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/categories?post=37"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/tags?post=37"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}