<?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>Entity Framework Design : Providers</title><link>http://blogs.msdn.com/efdesign/archive/tags/Providers/default.aspx</link><description>Tags: Providers</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Code Only – Further Enhancements</title><link>http://blogs.msdn.com/efdesign/archive/2009/10/12/code-only-further-enhancements.aspx</link><pubDate>Mon, 12 Oct 2009 17:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9906285</guid><dc:creator>efdesign</dc:creator><slash:comments>26</slash:comments><comments>http://blogs.msdn.com/efdesign/comments/9906285.aspx</comments><wfw:commentRss>http://blogs.msdn.com/efdesign/commentrss.aspx?PostID=9906285</wfw:commentRss><description>&lt;P&gt;We’ve come a long way since the &lt;A href="http://blogs.msdn.com/efdesign/archive/2009/08/03/code-only-enhancements.aspx" mce_href="http://blogs.msdn.com/efdesign/archive/2009/08/03/code-only-enhancements.aspx"&gt;last post on Code-Only&lt;/A&gt;. So it’s high time for another update.&lt;/P&gt;
&lt;P&gt;We’ve been working really hard on Code-Only revving the design, and spotting missing capabilities and responding to feedback both internal and external etc.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;The current plan still holds.&amp;nbsp; Code-Only will not be in .Net 4.0 with the possible exception of the DDL features described in the last post.&amp;nbsp; For that portion, the implementation and requirements are more clear to us, and because making the DDL stuff work requires changes to things already in the .NET framework, and getting provider writers lined up, we are still working hard to get the DDL changes into .NET 4.0.&amp;nbsp; The rest of Code-Only will continue to evolve, and we will ship another preview or two, before getting it rolled into .NET as soon as we can after 4.0 ships. &lt;/P&gt;
&lt;H3&gt;&lt;/H3&gt;
&lt;H3&gt;&lt;/H3&gt;
&lt;H3&gt;API Refactoring&lt;/H3&gt;
&lt;P&gt;As hinted above, we’ve spent a lot of time validating code only against real world scenarios, and thinking about how the customer code hangs together etc. As a results we’ve done some API refactoring.&lt;/P&gt;
&lt;H4&gt;Mappings are now part of Configurations&lt;/H4&gt;
&lt;P&gt;In the last version Mappings were derived from Configurations, which had some strange side-effects on the API. &lt;/P&gt;
&lt;P&gt;We’ve re-arranged things now so that Configurations hold mappings, which are terminated by assignment to a table.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.Entity&amp;lt;Customer&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .HasKey(c =&amp;gt; c.ID) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapSingleType(c =&amp;gt; new { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cid = c.ID, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nme = c.Name &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp; ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.custs”);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This maps the Customer entity to the ‘dbo.Custs’ table, the ID property to the cid column, the Name property to the nme column, and registers the ID property as the EntityKey / Primary Key.&lt;/P&gt;
&lt;P&gt;As you can see we’ve also added a helper method called Entity&amp;lt;TEntity&amp;gt;() so that you can fluently create configurations and mappings. You might also have noticed that we have removed RegisterKey and replaced it with HasKey which we feel is more inline with our goal of having an intentional API.&lt;/P&gt;
&lt;H4&gt;TPH mapping syntax no longer violates DRY&lt;/H4&gt;
&lt;P&gt;The previous syntax for specifying a &lt;A href="http://blogs.msdn.com/alexj/archive/2009/04/15/tip-12-choosing-an-inheritance-strategy.aspx" mce_href="http://blogs.msdn.com/alexj/archive/2009/04/15/tip-12-choosing-an-inheritance-strategy.aspx"&gt;TPH&lt;/A&gt; mapping forced you to repeat mappings for columns that could easily have been inherited.&lt;/P&gt;
&lt;P&gt;This was unfortunate because we normally encourage TPH because generally it has the best performance characteristics.&lt;/P&gt;
&lt;P&gt;This is where MapHierarchy() and Case() come in. &lt;/P&gt;
&lt;P&gt;Imagine if we want to write these classes using TPH:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;public class Person{ &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual int ID {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual string Firstname {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual string Surname {get;set;} &lt;BR&gt;} &lt;BR&gt;public class Employee: Person &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual Employee Manager {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual List&amp;lt;Employee&amp;gt; Reports {get;set;} &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;You would now do it like this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Entity&amp;lt;Person&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .HasKey(p =&amp;gt; p.ID) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapHierarchy() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Case&amp;lt;Person&amp;gt;( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p =&amp;gt; new { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p.ID, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p.Firstname,&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p.Surname, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thisIsADiscriminator = “P” &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp; ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Case&amp;lt;Employee&amp;gt;( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e =&amp;gt; new { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; manager = e.Manager.Id &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thisIsADiscriminator = “E” &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp; ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.People”);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;By using Case&amp;lt;&amp;gt; mappings are re-used for derived type, so there is no need to repeat column mappings for ID, Firstname and Surname. &lt;/P&gt;
&lt;P&gt;Which means the Employee Case statement is only responsible for mapping properties and references declared by the Employee class, and for specifying a new discriminator value. &lt;/P&gt;
&lt;P&gt;The discriminator column and values are there so the Entity Framework can distinguish between rows in the dbo.People table that represent Person objects and those that represent Employee objects.&lt;/P&gt;
&lt;H4&gt;MapSingleType and MapHierarchy&lt;/H4&gt;
&lt;P&gt;Because Mappings are now part of the configuration, there is no need to create them independently and assign them. &lt;/P&gt;
&lt;P&gt;You now simply MapXXX() methods on the EntityConfiguration.&lt;/P&gt;
&lt;P&gt;The available mapping methods are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;MapSingleType(λ) &lt;/LI&gt;
&lt;LI&gt;MapHierarchy(λ) &lt;/LI&gt;
&lt;LI&gt;MapHierarchy().Case&amp;lt;TEntity&amp;gt;(λ).Case&amp;lt;TDerived&amp;gt;(λ). &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;If you know the Entity Frameworks MSL files these correspond to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Type &lt;/LI&gt;
&lt;LI&gt;OfType &lt;/LI&gt;
&lt;LI&gt;OfType with an addition requirement for a type discriminator &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;These mappings can be combined in many interesting ways, but in general this table shows the recommended way to do most common mappings:&lt;/P&gt;
&lt;TABLE border=1 cellSpacing=0 cellPadding=2 width=426 height=544&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=96&gt;&lt;B&gt;Scenario&lt;/B&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=184&gt;&lt;B&gt;Code &lt;BR&gt;&lt;/B&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=268&gt;&lt;B&gt;Notes&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=96&gt;No Inheritance&lt;/TD&gt;
&lt;TD vAlign=top width=184&gt;builder.Entity&amp;lt;A&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapSingleType(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.A”); &lt;BR&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=268&gt;Columns not mapped are not part of the Entity.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=96&gt;TPH&lt;/TD&gt;
&lt;TD vAlign=top width=184&gt;builder.Entity&amp;lt;A&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapHierarchy() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Case&amp;lt;A&amp;gt;(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Case&amp;lt;B&amp;gt;(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Case&amp;lt;C&amp;gt;(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.ABC”); &lt;BR&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=268&gt;Generally each Case expression only maps properties declared by the current type and the discriminator for that type. &lt;BR&gt;&lt;BR&gt;But it is possible to override the mapping for inherited properties if required. &lt;BR&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=96&gt;TPT&lt;/TD&gt;
&lt;TD vAlign=top width=184&gt;builder.Entity&amp;lt;A&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapHierarchy(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.A”); &lt;BR&gt;&lt;BR&gt;builder.Entity&amp;lt;B&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapHierarchy(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.B”); &lt;BR&gt;&lt;BR&gt;builder.Entity&amp;lt;C&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapHierarchy(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.C”); &lt;BR&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=268&gt;Each MapHierarchy expression only maps properties declared by the current type, and properties that make up the entity key.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=96&gt;TPC&lt;/TD&gt;
&lt;TD vAlign=top width=188&gt;builder.Entity&amp;lt;A&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapSingleType(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.A”); &lt;BR&gt;&lt;BR&gt;builder.Entity&amp;lt;B&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapSingleType(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.B”); &lt;BR&gt;&lt;BR&gt;builder.Entity&amp;lt;C&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .MapSingleType(λ) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .ToTable(“dbo.C”); &lt;BR&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=268&gt;Each MapSingleType expression maps all properties, both those declared by the current type and those inherited.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;H3&gt;Foreign Keys&lt;/H3&gt;
&lt;P&gt;In Beta2 of .NET 4.0 we added &lt;A href="http://blogs.msdn.com/efdesign/archive/2009/03/16/foreign-keys-in-the-entity-framework.aspx" mce_href="http://blogs.msdn.com/efdesign/archive/2009/03/16/foreign-keys-in-the-entity-framework.aspx"&gt;FK Association Support&lt;/A&gt;, so Code-Only needs a way to link a FK property and an Navigation Property together.&lt;/P&gt;
&lt;P&gt;Given this class:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;public class Product{ &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual int ID {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual string Name {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual Category Category {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual int CategoryID {get;set;} &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;You need to be able to tell code-only that Category.ID and CategoryID should have the same value.&lt;/P&gt;
&lt;P&gt;You do it like this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.Entity&amp;lt;Product&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Relationship(p =&amp;gt; p.Category) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .HasConstraint((p,c) =&amp;gt; p.CategoryID == c.ID);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This says that c.ID (i.e. p.Category.ID) must equal p.CategoryID, which tells code-only that p.CategoryID is an FK property and p.Category is a navigation property backed by this FK property.&lt;/P&gt;
&lt;P&gt;HasConstraint(λ) can also be used in conjunction with Relationship(λ).FromProperty(λ) like this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.Entity&amp;lt;Product&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Relationship(p =&amp;gt; p.Category) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .FromProperty(c =&amp;gt; c.Products) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .HasConstraint((p,c) =&amp;gt; p.CategoryID == c.ID);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Verd&gt;Which tells code only that Product.Category and Category.Products are inverses and that Product.CategoryID and Product.Category.ID must be the same, which implies Product.CategoryID is an FK property.&lt;/FONT&gt;&lt;/P&gt;
&lt;H3&gt;Missing Navigation Properties&lt;/H3&gt;
&lt;P&gt;Sometimes you don’t have a navigation property or FK property in the Entity which would naturally hold the FK in the database. For example imagine this scenario:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;public class Product{ &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual int ID {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual string Name {get;set;} &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;public class Category{ &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual int ID {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual string Name {get;set;} &lt;BR&gt;&amp;nbsp;&amp;nbsp; public virtual List&amp;lt;Product&amp;gt; Products {get;set;} &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Here there is ‘probably’ a one to many relationship between Categories and Products, and that is probably best modeled using an FK in the products table. &lt;/P&gt;
&lt;P&gt;If you start mapping the Product entity you need a way to map the FK column, but there is no reference (i.e. Product.Category) and no FK property (i.e. Product.CategoryID) to map. &lt;/P&gt;
&lt;P&gt;So we added the ability to create a fake navigation property to help out:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.Entity&amp;lt;Product&amp;gt;().MapSingleType( &lt;BR&gt;&amp;nbsp;&amp;nbsp; p =&amp;gt; new { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pid = p.ID, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nme = p.Name &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cid = EntityMap.Related&amp;lt;Category&amp;gt;(c =&amp;gt; c.Products).ID &lt;BR&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;).ToTable(“dbo.Products”);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Here the interesting part is EntityMap.Related, it creates a fake navigation property, just so you can use it in the mapping.&lt;/P&gt;
&lt;P&gt;The method signature looks like this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;public static TEntity Related&amp;lt;TEntity&amp;gt;( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Expression&amp;lt;Func&amp;lt;TEntity, object&amp;gt; &lt;BR&gt;);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Notice that this function simply returns TEntity, so in the above mapping fragment, we are mapping the ID property of the Category class to the cid column, in the ‘dbo.Products’ table.&lt;/P&gt;
&lt;H3&gt;Complex Types&lt;/H3&gt;
&lt;P&gt;Code-Only’s default behavior is to ignore properties that are not recognized as either a primitive type or an EntityType. So to support Complex Types we need a mechanism to register one, like this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;var addressConf = builder.ComplexType&amp;lt;Address&amp;gt;();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This returns a ComplexTypeConfiguration through which you can configure the properties of the ComplexType in the same way you configure the properties of an Entity:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;addressConf.Property(a =&amp;gt; a.Street).HasMaxLength(100); &lt;BR&gt;addressConf.Property(a =&amp;gt; a.Zip).HasMaxLength(10);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Now if an entity is mapped by convention and it has a ComplexType property we will automatically introduce columns for each property of the ComplexType.&lt;/P&gt;
&lt;P&gt;If you want to explicitly map the Entity mapping the ComplexType property is pretty simple too:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.Entity&amp;lt;Person&amp;gt;().MapSingleType( &lt;BR&gt;&amp;nbsp;&amp;nbsp; p =&amp;gt; new { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p.ID, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fn = p.Firstname, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sn = p.Surname, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; street = p.Address.Street, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; zip = p.Address.Zip &lt;BR&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;);&lt;/FONT&gt;&lt;/P&gt;
&lt;H3&gt;Registering Entity Sets&lt;/H3&gt;
&lt;P&gt;Some of our early CodeOnly adopters wanted to use Code Only without having an specialized ObjectContext, and in theory with is possible:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder = contextBuilder.Create&amp;lt;ObjectContext&amp;gt;(); &lt;BR&gt;builder.Entity&amp;lt;Person&amp;gt;().HasKey(p =&amp;gt; p.ID);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;But what we found is you have no control over the name of the set generated. In this case we will generate an EntitySet called PersonSet, but what if I the name should be People?&lt;/P&gt;
&lt;P&gt;To address this issues we have added this method:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.RegisterSet&amp;lt;Person&amp;gt;(“People”);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Not only is this useful for specifying names,&amp;nbsp; it also allows you to intentional specify what EntitySets you need. The alternative would be to encode your intent into calls to Entity&amp;lt;TEntity&amp;gt; and Relationship&amp;lt;TRelated&amp;gt;(..).&lt;/P&gt;
&lt;H3&gt;Association Mapping&lt;/H3&gt;
&lt;P&gt;We also need to add support for mapping associations that are not co-located with the Entity. For example take the relationship between Jobs and Candidates. If a candidate can apply for multiple jobs this is a classic example of a many to many relationship. &lt;/P&gt;
&lt;P&gt;If you want to take control of how this relationship is mapped you need a way to specify the mapping for the relationship, like this:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder &lt;BR&gt;&amp;nbsp; .Entity&amp;lt;Job&amp;gt;() &lt;BR&gt;&amp;nbsp; .Relationship(job =&amp;gt; job.Applicants) &lt;BR&gt;&amp;nbsp; .FromProperty(candidate =&amp;gt; candidate.Applications) &lt;BR&gt;&amp;nbsp; .Map(“dbo.JobApplications”, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (job,candidate) =&amp;gt; new { &lt;BR&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; applicantId = candidate.Id, &lt;BR&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; jobId = job.Id &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This does a number of things, first it indicates that Job.Candidates and Candidate.Applications are opposite ends of the same relationship.&lt;/P&gt;
&lt;P&gt;Then the Map() call indicates that the relationship should be stored in the “dbo.JobApplications” join table, with a compound PK made up of the applicantId and jobId columns. &lt;/P&gt;
&lt;P&gt;The applicantId holds the candidate.Id, and the jobId holds the job.Id, and in both cases Code Only will emit an FK constraint to ensure referential integrity.&amp;nbsp; &lt;/P&gt;
&lt;H3&gt;Interesting Column Names&lt;/H3&gt;
&lt;P&gt;The existing mapping syntax that uses anonymous types for the table and column definitions, limits you to column names that are valid CLR identifiers.&lt;/P&gt;
&lt;P&gt;So for example if you need to map to a column with a space in the name you can’t.&lt;/P&gt;
&lt;P&gt;To rectify this we added an alternate mapping syntax:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder.Entity&amp;lt;Product&amp;gt;().MapSingleType( &lt;BR&gt;&amp;nbsp;&amp;nbsp; p =&amp;gt; EntityMap.Row( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EntityMap.Column(p.ID, “p i d”), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EntityMap.Column(p.Name), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EntityMap.Column(p.CategoryId, “c i d”) &lt;BR&gt;&amp;nbsp;&amp;nbsp; ) &lt;BR&gt;).ToTable(“dbo.Products”);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This snippet of code, maps the Product entity to the “dbo.Products” table and the ID property to a ‘p i d’ column, the Name property to a Name column and the CategoryId property to the ‘c i d’ column.&lt;/P&gt;
&lt;P&gt;This alternate API has another advantage too: it makes it easier to create mapping expressions programmatically, primarily because you no longer need to create an anonymous type when building the expression. Which is really useful if you want to configure code-only at runtime. &lt;/P&gt;
&lt;H3&gt;Extracting the EDMX&lt;/H3&gt;
&lt;P&gt;We’ve also added the ability to get the EDMX that Code Only is producing internally, either via an XmlWriter or as an XDocument:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;DbConnection connection = // some code to get a connection. &lt;BR&gt;XDocument document = builder.GetEdmx(connection);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;// or using XmlWriter &lt;BR&gt;var swriter = new StringWriter(); &lt;BR&gt;var xwriter = new XmlTextWriter(swriter); &lt;BR&gt;builder.WriteEdmx(connection, xwriter); &lt;BR&gt;&lt;/FONT&gt;&lt;BR&gt;This is pretty handy if you want to use Code Only to build your model and mappings but then pull them out so you work with the XML and our designer tooling.&lt;/P&gt;
&lt;H3&gt;Setting the StoreType&lt;/H3&gt;
&lt;P&gt;When producing the Storage Model Code Only asks the current database provider to return an appropriate store type for the CLR type and facets specified.&lt;/P&gt;
&lt;P&gt;But some CLR types and facet combinations can map to multiple possible database types. For example fixed length byte[] can map to both binary and timestamp. So in this situation SqlClient returns binary by default. &lt;/P&gt;
&lt;P&gt;But you might need a timestamp:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;builder &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Entity&amp;lt;Order&amp;gt;() &lt;BR&gt;&amp;nbsp;&amp;nbsp; .Property(o =&amp;gt; o.Version)&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp; .HasStoreType(“timestamp”) &lt;BR&gt;&amp;nbsp;&amp;nbsp; .IsComputed();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This tells Code Only that the Version property of Order (which is a byte[]) is computed in the database, and is actually a ‘timestamp’ column, which is computed in the database after every insert / update.&lt;/P&gt;
&lt;H3&gt;DDL Provider Model&lt;/H3&gt;
&lt;P&gt;In our &lt;A href="http://blogs.msdn.com/efdesign/archive/2009/10/06/extending-the-entity-framework-provider-model-to-support-ddl.aspx" mce_href="http://blogs.msdn.com/efdesign/archive/2009/10/06/extending-the-entity-framework-provider-model-to-support-ddl.aspx"&gt;last post&lt;/A&gt; we covered our plans around the DDL provider model, so check that out. &lt;/P&gt;
&lt;H3&gt;Summary&lt;/H3&gt;
&lt;P&gt;As you can see Code Only is now looking much more complete.&lt;/P&gt;
&lt;P&gt;But it isn’t completely finished yet, we are still working on the rough edges, so as always we are very interested to get your feedback. &lt;/P&gt;
&lt;P&gt;In particular are there things you think we should add / rename / simplify?&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/alexj" mce_href="http://blogs.msdn.com/alexj"&gt;&lt;B&gt;Alex James&lt;/B&gt;&lt;/A&gt; &lt;BR&gt;Program Manager, Entity Framework Team, Microsoft. &lt;BR&gt;&lt;B&gt;&lt;I&gt;&lt;BR&gt;This post is part of the transparent design exercise in the Entity Framework Team. To understand how it works and how your feedback will be used please look at &lt;/I&gt;&lt;/B&gt;&lt;A href="http://blogs.msdn.com/efdesign/archive/2008/06/23/transparency-in-the-design-process.aspx" mce_href="http://blogs.msdn.com/efdesign/archive/2008/06/23/transparency-in-the-design-process.aspx"&gt;&lt;B&gt;&lt;I&gt;this post&lt;/I&gt;&lt;/B&gt;&lt;/A&gt;&lt;B&gt;&lt;I&gt;. &lt;/I&gt;&lt;/B&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9906285" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/efdesign/archive/tags/Entity+Framework/default.aspx">Entity Framework</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Providers/default.aspx">Providers</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Mapping/default.aspx">Mapping</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/CodeOnly/default.aspx">CodeOnly</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Entity+Framework+Futures/default.aspx">Entity Framework Futures</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/What_2700_s+New/default.aspx">What's New</category></item><item><title>Extending the Entity Framework Provider Model to support DDL</title><link>http://blogs.msdn.com/efdesign/archive/2009/10/06/extending-the-entity-framework-provider-model-to-support-ddl.aspx</link><pubDate>Tue, 06 Oct 2009 21:24:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9903877</guid><dc:creator>efdesign</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/efdesign/comments/9903877.aspx</comments><wfw:commentRss>http://blogs.msdn.com/efdesign/commentrss.aspx?PostID=9903877</wfw:commentRss><description>&lt;p&gt;As part of the first previews of &lt;a href="http://blogs.msdn.com/efdesign/archive/2009/08/03/code-only-enhancements.aspx"&gt;Code-Only&lt;/a&gt; we shared some code to create a database:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;// Create a context using code-only      &lt;br /&gt;using (var mycontext = builder.Create(dbConnection))       &lt;br /&gt;{       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Create the database if it doesn’t already exist       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (!myContext.DatabaseExists())       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; myContext.CreateDatabase();       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Standard EF code goes here.       &lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;But in the first preview of Code-Only this code only worked against SQL Server. &lt;/p&gt;  &lt;p&gt;The problem is that our public Provider Model (i.e. &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.common.dbproviderservices.aspx"&gt;DbProviderServices&lt;/a&gt;) has no Database Definition Language or DDL features.&lt;/p&gt;  &lt;h5&gt;Provider Model Changes&lt;/h5&gt;  &lt;p&gt;To support DDL features across different databases, we plan to extend DbProviderServices, with DDL specific services.&lt;/p&gt;  &lt;p&gt;These services will be accessed through these public methods:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public string CreateDatabaseScript(      &lt;br /&gt;&amp;#160;&amp;#160; string providerManifestToken,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public void CreateDatabase(      &lt;br /&gt;&amp;#160;&amp;#160; DbConnection connection,       &lt;br /&gt;&amp;#160;&amp;#160; int? commandTimeout,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public bool DatabaseExists(      &lt;br /&gt;&amp;#160;&amp;#160; DbConnection connection,       &lt;br /&gt;&amp;#160;&amp;#160; int? commandTimeout,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public void DeleteDatabase(      &lt;br /&gt;&amp;#160;&amp;#160; DbConnection connection,       &lt;br /&gt;&amp;#160;&amp;#160; int? commandTimeout,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Now internally those methods will call through to the following ‘protected virtual’ methods which will do the actual work: &lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;protected virtual string DbCreateDatabaseScript(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; string providerManifestToken,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;protected virtual void DbCreateDatabase(      &lt;br /&gt;&amp;#160;&amp;#160; DbConnection connection,       &lt;br /&gt;&amp;#160;&amp;#160; int? commandTimeout,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;protected virtual bool DbDatabaseExists(      &lt;br /&gt;&amp;#160;&amp;#160; DbConnection connection,       &lt;br /&gt;&amp;#160;&amp;#160; int? commandTimeout,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;protected virtual void DbDeleteDatabase(      &lt;br /&gt;&amp;#160;&amp;#160; DbConnection connection,       &lt;br /&gt;&amp;#160;&amp;#160; int? commandTimeout,       &lt;br /&gt;&amp;#160;&amp;#160; StoreItemCollection storeItemCollection);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;And the base implementations of these methods in DbProviderServices will simply throw ProviderIncompatibleExceptions. &lt;/p&gt;  &lt;p&gt;Which means the provider writers job will be to override these ‘protected virtual’ methods with an implementation that makes sense for their backend database.&lt;/p&gt;  &lt;p&gt;The key is to understand that the &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.storeitemcollection.aspx"&gt;StoreItemCollection&lt;/a&gt; (aka the SSDL or StorageModel part of the EDMX) represents the intended shape of the database. &lt;/p&gt;  &lt;p&gt;This means the provider writer will need to iterate over the EntitySets (tables) and the corresponding EntityTypes (table structures) in the StoreItemCollection and create / drop / script the database and tables as required.&lt;/p&gt;  &lt;p&gt;Provider writers will be expected to override these functions so that:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;DbCreateDatabaseScript:&lt;/strong&gt; creates a native text command to create the tables and foreign key constraints defined in the StoreItemCollection. I.e. for SqlClient this would be the contents of a .sql DDL file. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;DbCreateDatabase:&lt;/strong&gt; is similar to DbCreateDatabaseScript except it should actually goes ahead and create the database, tables and foreign key constraints. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;DbDatabaseExists:&lt;/strong&gt; checks to see if the database exists. The SqlClient provider will simply check that the database itself exists, but custom provider writers could get more fancy and check to see if every table / foreign key constraint is found too. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;DbDeleteDatabase:&lt;/strong&gt; should go ahead and delete the database, or if the database server has a single database model (like Oracle) the provider writer should delete just the tables defined in the StoreItemCollection. &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Simplifying Wrapping Providers&lt;/h5&gt;  &lt;p&gt;We are also planning something to simplify writing Wrapping Providers. A wrapping provider is just a provider that wraps an existing provider (i.e. SqlClient) and adds additional services (i.e. Auditing, Logging, Caching etc). &lt;/p&gt;  &lt;p&gt;Jarek has some &lt;a href="http://blogs.msdn.com/jkowalski/archive/2009/06/11/tracing-and-caching-in-entity-framework-available-on-msdn-code-gallery.aspx"&gt;some sample wrapping providers&lt;/a&gt; if you are interested.&lt;/p&gt;  &lt;p&gt;Today writing a wrapping provider is a little tricky, in fact one ‘protected’ method is impossible to wrap without reflection. So to help we plan to add one public wrapper method:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public DbCommandDefinition CreateCommandDefinition(      &lt;br /&gt;&amp;#160;&amp;#160; DbProviderManifest providerManifest,       &lt;br /&gt;&amp;#160;&amp;#160; DbCommandTree commandTree);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;One of the reasons we plan on doing this, is we think people might take a ‘basic’ provider that has no DDL support and wrap it to add DDL support.&lt;/p&gt;  &lt;h5&gt;End User API&lt;/h5&gt;  &lt;p&gt;Now so far we’ve been looking at the planned extensions to Provider Services, but Provider Services is a very low level API that few developers will ever program against.&lt;/p&gt;  &lt;p&gt;Most people will work directly against the ObjectContext, to which we plan to add these methods:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public void CreateDatabase()&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public void DeleteDatabase();&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public bool DatabaseExists();&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;public String CreateDatabaseScript();&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;This little snippet shows how easy it will be to script, create, check and delete a database:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;MyContext ctx = new MyContext();      &lt;br /&gt;String sql = ctx.CreateDatabaseScript();       &lt;br /&gt;ctx.CreateDatabase();       &lt;br /&gt;Assert.True(ctx.DatabaseExists());       &lt;br /&gt;ctx.DeleteDatabase();       &lt;br /&gt;Assert.False(ctx.DatabaseExists());&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;As you it could hardly be easier to use.&lt;/p&gt;  &lt;h5&gt;Summary:&lt;/h5&gt;  &lt;p&gt;While Code-Only provides the catalyst to add DDL support to the Entity Framework’s Provider model, this feature is about &lt;a href="http://blogs.msdn.com/alexj/archive/2009/08/12/tip-32-how-to-create-a-database-from-ssdl-ef-4-only.aspx"&gt;more than just Code-Only&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;In fact we think this feature will add significantly to the usability of the Entity Framework. &lt;/p&gt;  &lt;p&gt;But as always we are keen to hear what you think.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/alexj"&gt;&lt;b&gt;Alex James&lt;/b&gt;&lt;/a&gt;     &lt;br /&gt;Program Manager, Entity Framework Team, Microsoft.     &lt;br /&gt;&lt;b&gt;&lt;i&gt;       &lt;br /&gt;This post is part of the transparent design exercise in the Entity Framework Team. To understand how it works and how your feedback will be used please look at &lt;/i&gt;&lt;/b&gt;&lt;a href="http://blogs.msdn.com/efdesign/archive/2008/06/23/transparency-in-the-design-process.aspx"&gt;&lt;b&gt;&lt;i&gt;this post&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;&lt;b&gt;&lt;i&gt;. &lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9903877" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/efdesign/archive/tags/Entity+Framework/default.aspx">Entity Framework</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Providers/default.aspx">Providers</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/CodeOnly/default.aspx">CodeOnly</category></item><item><title>Transparent Caching Support in the Entity Framework</title><link>http://blogs.msdn.com/efdesign/archive/2008/07/09/transparent-caching-support-in-the-entity-framework.aspx</link><pubDate>Wed, 09 Jul 2008 23:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8713777</guid><dc:creator>efdesign</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/efdesign/comments/8713777.aspx</comments><wfw:commentRss>http://blogs.msdn.com/efdesign/commentrss.aspx?PostID=8713777</wfw:commentRss><description>&lt;P&gt;The&amp;nbsp;Entity Framework's provider model makes it possible for it to work over different database's. &lt;/P&gt;
&lt;P&gt;The idea being that someone, either the database vendor or a third party, can write a provider that allows the Entity Framework to work with that database.&lt;/P&gt;
&lt;P&gt;The Entity Framework asks the provider to convert queries and update operations from a canonical, database agnostic form, into native commands. I.e. T-SQL for SQLServer.&lt;/P&gt;
&lt;P&gt;This Provider model however has an interesting side-effect. It makes it possible to write wrapping providers, providers that wrap another provider, layering in additional services. &lt;/P&gt;
&lt;P&gt;Examples of possible wrapping providers include: logging providers, auditing providers, security providers, optimizing providers and caching providers. The latter&amp;nbsp;is the subject of the following one-pager put together by &lt;A class="" href="http://blogs.msdn.com/jkowalski/" mce_href="http://blogs.msdn.com/jkowalski/"&gt;Jarek&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;----&lt;/P&gt;
&lt;H3&gt;Introduction&lt;/H3&gt;
&lt;P class=MsoNormal&gt;Business applications use various kinds of Reference Data that does not change at all during the lifetime of an application or changes very infrequently. Examples may include: countries, cities, regions, product categories, etc.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Applications that present data (such as ASP.NET applications) tend to run the same or similar queries for reference data very often resulting in a significant database load. Developers typically use ASP.NET cache and/or custom caching techniques to minimize number of queries but implementing caching manually adds additional complexity and maintenance cost to an existing solution.&lt;/P&gt;
&lt;P class=MsoNormal&gt;Entity Framework can be extended to handle data caching in a transparent way, so that any application using it can take advantage of caching with little or no modification. In Entity Framework V1 it is possible to implement transparent caching using a custom provider as demonstrated in EFCachingProvider sample (TBD). We are considering adding caching as a first-class concept in Entity Framework V2 so that it will no longer be necessary to use a wrapper provider approach.&lt;/P&gt;
&lt;H3&gt;Requirements&lt;/H3&gt;
&lt;P class=MsoNormal&gt;We are designing a query caching layer for Entity Framework that:&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpFirst style="TEXT-INDENT: -0.25in; mso-list: l1 level1 lfo1"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;Will be transparent (existing code will automatically take advantage of caching without modification other than defining caching policy).&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="TEXT-INDENT: -0.25in; mso-list: l1 level1 lfo1"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;Will cache query results, not entity objects so arbitrary ESQL queries can also benefit from it&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="TEXT-INDENT: -0.25in; mso-list: l1 level1 lfo1"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;Will be optimized for read-only or mostly-read-only data. Caching of frequently changing data will also be supported, but we are not optimizing for that scenario.&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="TEXT-INDENT: -0.25in; mso-list: l1 level1 lfo1"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;Will handle cache eviction automatically on updates.&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpLast style="TEXT-INDENT: -0.25in; mso-list: l1 level1 lfo1"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;Will be extensible (it should be easy to use with ASP.NET cache or &lt;SUP&gt;3rd&lt;/SUP&gt; party caching solutions including local and distributed caches)&lt;/P&gt;
&lt;H3&gt;Implementation&lt;/H3&gt;
&lt;P class=MsoNormal&gt;To implement query caching we need to be able to intercept query and update execution.&lt;/P&gt;
&lt;P class=MsoNormal&gt;All queries in Entity Framework (regardless of their origin: Entity SQL queries, Object Query&amp;lt;T&amp;gt;, LINQ queries or internal queries generated by object layer) are processed in the Query Pipeline which at some point passes Canonical Query Tree (CQT) to the provider to get the result set of a query. We will cache query results in such a way that when the same query is used over and over again (as determined by the CQT and parameter values), the results will be assembled from the cache instead of a database. &lt;/P&gt;
&lt;P class=MsoNormal&gt;Updates are also centralized in Entity Framework (Update Pipeline) and handled in a similar way. At some point update commands (Update CQTs) are sent to the provider. We can add cache maintenance routines at this point that ensure that proper cache invalidation happens each time an update occurs.&lt;/P&gt;
&lt;H3&gt;Cache entries and dependencies&lt;/H3&gt;
&lt;P class=MsoNormal&gt;Query results stored in the cache will be represented by opaque data structures, which are immutable and serializable, so that they can be easily passed over the wire. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;An example of such structure may be:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;[&lt;SPAN style="COLOR: #2b91af"&gt;Serializable&lt;/SPAN&gt;] &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;DbQueryResults &lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;{ &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;[]&amp;gt; Rows = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;[]&amp;gt;(); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;}&lt;/SPAN&gt; 
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;When caching query results care must be taken to make sure that returned data is not stale. To be able to detect that, we associate a list of dependencies with each query result. Whenever any of the dependencies change, the query results should be evicted from cache. In the proposed approach, dependencies will be simply store-level entity set names (tables or views) that are used in the query. &lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;For example: &lt;/P&gt;
&lt;P class=MsoListParagraphCxSpFirst style="TEXT-INDENT: -0.25in; mso-list: l2 level1 lfo2"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;B style="mso-bidi-font-weight: normal"&gt;SELECT c.Id FROM Customers AS c &lt;/B&gt;is dependent on “Customers” entity sets&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="TEXT-INDENT: -0.25in; mso-list: l2 level1 lfo2"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;B style="mso-bidi-font-weight: normal"&gt;SELECT c.Id, c.Orders FROM Customers as c &lt;/B&gt;is dependent on Customers and Orders entity sets&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpLast style="TEXT-INDENT: -0.25in; mso-list: l2 level1 lfo2"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;B style="mso-bidi-font-weight: normal"&gt;1+2&lt;/B&gt; is not dependent on any entity sets&lt;/P&gt;
&lt;P class=MsoNormal&gt;When adding items to the cache, we will be passing a list of dependent entity sets to the cache provider. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;After EF makes changes to the database, it will notify the cache about list of entity sets that have changed. All query results relying on any of those entity sets have to be removed from the cache. Dependency names will be represented as strings and collections of dependent entity sets will be &lt;SPAN style="FONT-SIZE: 10pt; COLOR: #2b91af; LINE-HEIGHT: 115%; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;IEnumerable&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt;&lt;/SPAN&gt;.&lt;/P&gt;
&lt;P class=MsoNormal&gt;In the first implementation we will likely use query text or some derivative of it (such as cryptographic hash) as a cache key, but cache implementations should not rely upon cache keys being meaningful.&lt;/P&gt;
&lt;H3&gt;Interface&lt;/H3&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;To be able to work with EF, cache must implement the following interface:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt; &lt;SPAN style="COLOR: blue"&gt;interface&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ICache &lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;{ &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;bool&lt;/SPAN&gt; TryGetEntryByKey(&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; key, &lt;SPAN style="COLOR: blue"&gt;out&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt; value); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;void&lt;/SPAN&gt; Add(&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; key, &lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt; value,&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt; dependentEntitySets); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;void&lt;/SPAN&gt; Invalidate(&lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt; entitySets); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;} 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;As you can see, the values are passed as objects instead of &lt;SPAN style="FONT-SIZE: 10pt; COLOR: #2b91af; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;DbQueryResults&lt;/SPAN&gt;. 
&lt;P class=MsoListParagraphCxSpFirst style="MARGIN-BOTTOM: 0pt; TEXT-INDENT: -0.25in; LINE-HEIGHT: normal; mso-layout-grid-align: none; mso-list: l0 level1 lfo3; mso-add-space: auto"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;B style="mso-bidi-font-weight: normal"&gt;TryGetEntryByKey(key,out value) &lt;/B&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;tries to get cache entry for a given key. If the entry is found it is returned in queryResults and the function returns true. If the entry is not found, the entry returns false and value of queryResults is not determined.&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="MARGIN-BOTTOM: 0pt; TEXT-INDENT: -0.25in; LINE-HEIGHT: normal; mso-layout-grid-align: none; mso-list: l0 level1 lfo3; mso-add-space: auto"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;B style="mso-bidi-font-weight: normal"&gt;Add (key, value, dependentEntitySets)&lt;/B&gt; adds the specified query results to the cache with and sets up dependencies on given entity sets.&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="MARGIN-BOTTOM: 0pt; TEXT-INDENT: -0.25in; LINE-HEIGHT: normal; mso-layout-grid-align: none; mso-list: l0 level1 lfo3; mso-add-space: auto"&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;SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; LINE-HEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal" roman?? new times&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;B style="mso-bidi-font-weight: normal"&gt;Invalidate(sets)&lt;/B&gt; – will be invoked after changes have been committed to the database. “sets” is a list of sets that have been modified. The cache should evict ALL queries whose dependencies include ANY of the modified sets.&lt;/P&gt;
&lt;P class=MsoNoSpacing&gt;Cache providers will typically define some specific retention policies, limits and automatic eviction policies (using LRU, LFU or some other criteria). &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: #2b91af; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;ICache&lt;/SPAN&gt; interface does not define that. Based on the user feedback we may want to extend &lt;SPAN style="FONT-SIZE: 10pt; COLOR: #2b91af; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;ICache &lt;/SPAN&gt;to specify parameters such as retention timeout for each item or add a new interface for configuring cache behavior in an abstract way.&lt;/P&gt;
&lt;P class=MsoNoSpacing&gt;Using the interface defined above, the pseudo-C#-code implementation of query execution operation may look like this:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN-BOTTOM: 0pt; LINE-HEIGHT: normal; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: #2b91af; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;DbQueryResults&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt; GetResultsFromCache(&lt;SPAN style="COLOR: #2b91af"&gt;DbCommandDefinition&lt;/SPAN&gt; query) &lt;BR&gt;{ &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; (CanBeCached(query)) &lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{ &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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: green"&gt;// calculate cache key &lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;string&lt;/SPAN&gt; cacheKey = GetCacheKey(query); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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: #2b91af"&gt;DbQueryResults&lt;/SPAN&gt; results; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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: green"&gt;// try to look up the results in the cache &lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;if&lt;/SPAN&gt; (!Cache.TryGetEntryByKey(cacheKey, &lt;SPAN style="COLOR: blue"&gt;out&lt;/SPAN&gt; results))&amp;nbsp; &lt;BR&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;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;&lt;SPAN style="COLOR: green"&gt;// results not found in the cache - perform a database query &lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;results = GetResultsFromDatabase(query); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;&lt;SPAN style="COLOR: green"&gt;// add results to the cache &lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;Cache.Add(cacheKey, results, GetDependentEntitySets(query)); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;return&lt;/SPAN&gt; results; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;} &lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;/SPAN&gt; &lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{ &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&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;return&lt;/SPAN&gt; GetResultsFromDatabase(query); &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;} &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " yes? mso-no-proof: new?; courier&gt;} 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;----&lt;/P&gt;
&lt;P&gt;As always we are keen to hear your comments.&lt;/P&gt;
&lt;P&gt;Alex James &lt;BR&gt;Program Manager, &lt;BR&gt;Entity Framework Team&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;EM&gt;This post is part of the transparent design exercise in the Entity Framework Team. To understand how it works and how your feedback will be used please look at &lt;/EM&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;EM&gt;&lt;A href="http://blogs.msdn.com/efdesign/archive/2008/06/23/transparency-in-the-design-process.aspx"&gt;&lt;FONT color=#4c6d7e&gt;this post&lt;/FONT&gt;&lt;/A&gt;&lt;/EM&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;EM&gt;. &lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8713777" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/efdesign/archive/tags/Entity+Framework/default.aspx">Entity Framework</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Providers/default.aspx">Providers</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Caching/default.aspx">Caching</category><category domain="http://blogs.msdn.com/efdesign/archive/tags/Entity+Framework+4/default.aspx">Entity Framework 4</category></item></channel></rss>