Entity Framework 5 http://blogs.ugidotnet.org/PietroLibroBlog/category/Entity Framework 5.aspx Entity Framework 5 it-IT Pietro Libro pietro.libro@libero.it Subtext Version 2.6.0.0 EF6 (beta1) - Code First Stored Procedures Mapping http://blogs.ugidotnet.org/PietroLibroBlog/archive/2013/06/26/ef6-beta1-code-first-stored-procedures-mapping.aspx <p>Una delle features che sicuramente in molti aspettavano con la nuova release di EF è la possibilità di eseguire il mapping delle entità tramite Stored Procedures. Con la versione 6 di Entity Framework (attualmente in beta 1), abbiamo finalmente questa possibilità, e l'utilizzo è veramente immediato.</p> <p>Supponiamo di avere un Domain Model simile a quello mostrato nella figura seguente:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/WindowsLiveWriter/EF6beta1CodeFirstStoredProceduresMapping_8648/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/WindowsLiveWriter/EF6beta1CodeFirstStoredProceduresMapping_8648/image_thumb.png" width="206" height="244" /></a> </p> <p>Dove abbiamo un insieme di oggetti ereditati, ed una <em>navigation property </em>che collega l'oggeto <em>Car</em> ad una collezione di oggetti <em>Optional</em>. </p> <p>Aggiungiamo il riferimento ad EF6 utilizzando il gestore di "NuGet Packages" selezionando tra le varie opzioni "Include Prerelease" e poi selezioniamo il package "Entity Framework":</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/WindowsLiveWriter/EF6beta1CodeFirstStoredProceduresMapping_8648/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/WindowsLiveWriter/EF6beta1CodeFirstStoredProceduresMapping_8648/image_thumb_1.png" width="244" height="150" /></a> </p> <p>Eseguiamo la configurazione delle classi che compongono il nostro Domain tramite Code First Fluent Api ed aggiungiamo il codice seguente:</p> <pre class="csharpcode"> modelBuilder.Entity&lt;Domain.Car&gt;().MapToStoredProcedures(); modelBuilder.Entity&lt;Domain.Optional&gt;().MapToStoredProcedures();</pre> <p> </p> <p>Il quale "informa" il run-time di Entity Framework che per le entità "Car" ed "Optional" le operazioni di Insert\Delete\Update verranno utilizzate delle Stored Procedures (che rispondono alle convenzioni richieste da EF). </p> <p>A questo punto entra in scena EF Migrations ed il "fantastico" comando "Add-Migration", che produce tutto il codice, e non solo, necessario ad aggiornare il database:</p> <pre class="csharpcode"> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Up() { CreateStoredProcedure( <span class="str">"DomusDotNet.Car_Insert"</span>, p =&gt; <span class="kwrd">new</span> { Brand = p.String(maxLength: 128), Model = p.String(maxLength: 128), EngineSize = p.String(maxLength: 128), HP = p.Int(), DailyRent = p.Single(), FreeDailyKm = p.Int(), Note = p.String(maxLength: 128), }, body: <span class="str">@"INSERT [DomusDotNet].[Vehicles]([Brand], [Model], [EngineSize], [HP], [DailyRent], [FreeDailyKm], [Note]) VALUES (@Brand, @Model, @EngineSize, @HP, @DailyRent, @FreeDailyKm, @Note) DECLARE @Id int SELECT @Id = [Id] FROM [DomusDotNet].[Vehicles] WHERE @@ROWCOUNT &gt; 0 and [Id] = scope_identity() INSERT [DomusDotNet].[Cars]([Id]) VALUES (@Id) SELECT t0.[Id] FROM [DomusDotNet].[Vehicles] as t0 WHERE @@ROWCOUNT &gt; 0 and t0.[Id] = @Id"</span> ); ...</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>Unico neo, se utilizzate uno schema diverso da "dbo" (anche se avete specificato tramite la nuova API HasDefaultSchema("...") lo schema corretto) bisogna modificare manualmente il nome delle Stored Procedures, altrimenti a run-time verrà generata un'eccezione.</p> <p>Scriviamo del codice di test tipo:</p> <pre class="csharpcode"><span class="kwrd">int</span> rowsAffected = 0; Domain.Car fordFocus = <span class="kwrd">new</span> Domain.Car() { Brand = <span class="str">"FORD"</span>, DailyRent = 45.0f, EngineSize = <span class="str">"1600"</span>, FreeDailyKm = 100, HP = 115, Model = <span class="str">"Focus"</span>, Note = <span class="str">"With Radio and Power Steering."</span> }; fordFocus.Optionals.Add(<span class="kwrd">new</span> Domain.Accesory() { Description = <span class="str">"Radio Sony"</span>, Removable = <span class="kwrd">true</span>, Price = 10 }); fordFocus.Optionals.Add(<span class="kwrd">new</span> Domain.Accesory() { Description = <span class="str">"Power Steering"</span>, Removable = <span class="kwrd">false</span>, Price = 0 }); <span class="kwrd">using</span> (Data.CarRentalDB db = <span class="kwrd">new</span> Data.CarRentalDB()) { db.Cars.Add(fordFocus); rowsAffected = db.SaveChanges(); }</pre> <p /><style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style>Utilizzando il nostro amico "Sql Profiler" vediamo come le operazioni di accesso alla tabella per Insert\Update\Delete utilizzano le Stored Procedures generate in precedenza: <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/WindowsLiveWriter/EF6beta1CodeFirstStoredProceduresMapping_8648/image_8.png"><img title="image" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/WindowsLiveWriter/EF6beta1CodeFirstStoredProceduresMapping_8648/image_thumb_3.png" width="244" height="130" /></a> </p> <p>Di questo ed altro parleremo in dettaglio durante l'evento <a href="mailto:EF@Work">EF@Work</a> organizzato da DomusDotNet :-)</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101596.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2013/06/26/ef6-beta1-code-first-stored-procedures-mapping.aspx Wed, 26 Jun 2013 10:30:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2013/06/26/ef6-beta1-code-first-stored-procedures-mapping.aspx#feedback 1 http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101596.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101596.aspx Web API: Circular Object References http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/08/22/web-api-circular-object-references.aspx <p>Quando utilizziamo le Web API, per leggere e scrivere oggetti nel corpo di un messaggio Http utilizziamo delle classi particolari, le media-type formatters. "Gratis" Web API fornisce media-type formatters per JSON e XML, utilizzate secondo della richiesta da parte dei client (“Accept”). Se JSON e XML non sono i "formati" di cui abbiamo bisogno possiamo sempre creare la nostra classe derivata da <em>MediaTypeFormatter</em> o <em>BufferedMediaTypeFormatter</em>, rispettivamente per scenari asincroni o sincroni, ma non sono l’argomento di questo post promemoria.</p> <p>Quando abbiamo a che fare con grafi di oggetti complessi, possono crearsi situazioni in cui abbiamo riferimenti circolari tra oggetti. Ad esempio in uno scenario di questo tipo:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/4c85039d270e_1360F/image_2.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/4c85039d270e_1360F/image_thumb.png" width="244" height="161" /></a></p> <p>Dove abbiamo due classi, Book ed Author , referenziate tramite <em>collection</em> (praticamente un’associazione molti-a-molti) l’una con l’altra. </p> <p>Se abbiamo una Web API di questo tipo :</p> <pre class="csharpcode"><span class="kwrd">private</span> BookshelfDb _db = <span class="kwrd">new</span> BookshelfDb(); <span class="kwrd">public</span> IEnumerable&lt;Book&gt; GetBooks() { <span class="kwrd">return</span> _db.Books.Include(b =&gt; b.Authors).AsEnumerable(); } ...</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>ed una configurazione standard delle Web API, ad eccezione dell’indentatura:</p> <pre class="csharpcode">JsonMediaTypeFormatter json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; json.Indent = <span class="kwrd">true</span>;</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>In presenza di dati, invocando GetBooks() (ad esempio tramite browser), otterremo un’eccezione di questo tipo:</p> <pre class="csharpcode">{ <span class="str">"Message"</span>: <span class="str">"An error has occurred."</span>, <span class="str">"ExceptionMessage"</span>: <span class="str">"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."</span>, <span class="str">"ExceptionType"</span>: <span class="str">"System.InvalidOperationException"</span>, <span class="str">"StackTrace"</span>: <span class="kwrd">null</span>, <span class="str">"InnerException"</span>: { <span class="str">"Message"</span>: <span class="str">"An error has occurred."</span>, <span class="str">"ExceptionMessage"</span>: <span class="str">"<strong>Self referencing loop detected with</strong> type 'BookshelfWebApi.Models.Book'. Path '[0].Authors[0].Books'."</span>, <span class="str">"ExceptionType"</span>: <span class="str">"Newtonsoft.Json.JsonSerializationException"</span>, <span class="str">"StackTrace"</span>: " … }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>La soluzione al problema è abbastanza semplice  in quanto è sufficiente aggiungere la riga:</p> <pre class="csharpcode">json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>Il caso Xml, non è immediato come nel caso JSON, in quanto è necessario decorare le classi con l’attributo <em>DataContract</em> impostando la proprietà <em>IsReference</em> a <em>true</em>. In questo caso però è necessario decorare anche le proprietà con l’attributo <em>DataMember</em>:</p> <pre class="csharpcode">[DataContract(IsReference = <span class="kwrd">true</span>)] <span class="kwrd">public</span> <span class="kwrd">class</span> Book { <span class="kwrd">public</span> Book() { <span class="kwrd">this</span>.Authors = <span class="kwrd">new</span> List&lt;Author&gt;(); } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">int</span> Id { get; set; } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">int</span> Paperback { get; set; } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">string</span> Title { get; set; } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">string</span> ISBN_10 { get; set; } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">string</span> ISBN_13 { get; set; } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">string</span> Language { get; set; } [DataMember()] <span class="kwrd">public</span> <span class="kwrd">string</span> Publisher { get; set; } [DataMember()] <span class="kwrd">public</span> ICollection&lt;Author&gt; Authors { get; set; } }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>Se non si vuole “sporcare” le classi “farcendole” di attributi possiamo optare per un <em>DataContractSerializer. </em>Le Web API possono essere configurate modificando il codice presente nella classe WebApiConfig.cs:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/4c85039d270e_1360F/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/4c85039d270e_1360F/image_thumb_1.png" width="244" height="225" /></a></p> <p>Quanto detto è sicuramente famigliare per chi espone entità collegate tramite Http, ad esempio utilizzando WCF.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101168.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/08/22/web-api-circular-object-references.aspx Wed, 22 Aug 2012 11:17:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/08/22/web-api-circular-object-references.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101168.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101168.aspx EF5 Released http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/08/16/ef5-released.aspx <p>Con l’arrivo in RTM di Windows 8 e Visual Studio 2012 è stata rilasciata la nuova versione di Entity Framework (scaricabile ovviamente tramite NuGet). Le novità presenti sono diverse, quella più “gettonata” è sicuramente il supporto agli “Enum”. Diverse novità coinvolgono anche il Designer di EF per Visual Studio 2012, come il supporto a diagrammi multipli per lo stesso modello (una delle funzionalità che più apprezzo).</p> <p> Per tutti i dettagli del caso, per la compatibilità delle funzioni utilizzabili secondo del targeting del .NET Framework, lista dei bug corretti ed altro, è possibile iniziare da <a href="http://blogs.msdn.com/b/adonet/archive/2012/08/15/ef5-released.aspx" target="_blank">qui</a>. </p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101156.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/08/16/ef5-released.aspx Thu, 16 Aug 2012 08:54:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/08/16/ef5-released.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101156.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101156.aspx EF5 RC http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/05/16/ef5-rc.aspx <p>Rilasciata la versione Release Candidate di Entity Framework 5. Il download al solito è disponibile tramite NuGet sia per .Net 4 (in questo caso alcune features non sono supportate, come Enum e Spatial Data) e .Net 4.5.</p> <p>Dettagli e nuovi  Walkthrough disponibili sul blog del team di <a href="http://blogs.msdn.com/b/adonet/archive/2012/05/15/ef5-release-candidate-available-on-nuget.aspx">ADO.NET</a>.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101003.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/05/16/ef5-rc.aspx Wed, 16 May 2012 10:58:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2012/05/16/ef5-rc.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101003.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101003.aspx