Mehr POCO (Plain Old CLR Objects) und Entity Framework - Der "Persistence Ignorance (POCO) Adapter for Entity Frmaework V1"

In diesem Blogs habe ich schon 2-mal über die Themen Entity Framework und POCO geschrieben. Aus meiner Sicht sind das interessante Themen, da das Entity Framework mit Linq einen guten und effizient programmierbaren Zugriffsweg auf relationale Daten bietet. Andererseits sind aus architektureller Sicht an vielen Stellen POCOs eine gute Lösung für die Implementierung von Business Entities oder Data Transfer Objects in einer Architektur.

Diese Überlegungen haben auch andere Architekten angestellt und einen sogenannten "Persistence Ignorance (POCO) Adapter for Entity Framework V1" erstellt. Dieser Adapter erlaubt die Verwendung von POCO's mit dem Entity Framework.

In seinem Blogeintrag schreibt Jaroslaw Kowalski über die Motivation und die Grundmechanismen des EfPocoAdapters --> https://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx

Der Code des Adapters (mit Tests und Minisample) kann auf der MSDN Code Seite heruntergeladen werde --> https://code.msdn.microsoft.com/EFPocoAdapter

Da ich bin der Nutzung des Adapters nicht sofort erfolgreich war, und es ein paar kleine Eigenheiten gab, will ich ganz kurz nochmal die Schritte beschreiben, die man machen muss, um den EfPocoAdapter zu nutzen.

Um die speziellen POCOs und den Zugriffsadapter für eine bestimmte Datenbank zu erzeugen, benötigt man ein Entity Framework EDMX Modell File ".EDMX" oder die Entity Framework ".CSDL/.SSDL/.MSDL" Files.

Für mein Sample habe ich mich für die CSDL Variante entschieden. Ein CSDL File für eine Datenbank kann man sich mit dem Tool EdmGen.exe erzeugen lassen. Dem Tool muss ein Connectionstring auf eine Datenbank, ein Zielnamespace und der Modus übergeben werden. Um sich die CSDL/SSDL/MSL Files auf einmal erzeugen zu lassen, startet man das EdmGen.exe Tool am besten mit dem "Fullgeneration" Modus.

Die Kommandzeile sieht so aus ...

 
C:\Windows\Microsoft.NET\Framework\v3.5\edmgen.exe 

/connectionstring:"Data Source=(local);Initial Catalog=Northwind;Integrated Security=True" 

/namespace:NorthwindPoco 

/mode:FullGeneration 

/project:NorthwindPocoEf

Nach diesem Aufruf hat man die notwendigen Entity Framework Files, um mit dem Generator des EfPocoAdapaters den notwendigen Code erzeugen zu lassen. Wichtig: Die erzeugten Files ".CSDL", ".SSDL" und ".MSL" müssen in das Projekt includiert werden und müssen zum Projekt Output Directory kopiert werden!

image

 

Mit der Kommandozeile ...

 c:\SdkSamples\EFPocoAdapter\EFPocoClassGen\bin\Debug\EFPocoClassGen.exe /incsdl:NorthwindPocoEf.csdl 
/mode:PocoClasses 

/outputfile:NorthwindPocoClasses.cs

erzeugt man die PoCo Klassen für die Datenbank. Ein typisches Beispiel für eine so generierte Klassen sind zum Beispiel das ...

    public class CustomerDemographics
    {
        public String CustomerTypeID { get; set; }
        public String CustomerDesc { get; set; }
        public IList<NorthwindPoco.Customers> Customers { get; set; } 
    }
    public class Customers
    {
        public String CustomerID { get; set; }
        public String CompanyName { get; set; }
        public String ContactName { get; set; }
        public String ContactTitle { get; set; }
        public String Address { get; set; }
        public String City { get; set; }
        public String Region { get; set; }
        public String PostalCode { get; set; }
        public String Country { get; set; }
        public String Phone { get; set; }
        public String Fax { get; set; }
        public DateTime? LastEditDate { get; set; }
        public DateTime? CreationDate { get; set; }
        public IList<NorthwindPoco.Orders> Orders { get; set; } 
        public IList<NorthwindPoco.CustomerDemographics> CustomerDemographics { get; set; } 
    }

 

In den fett markierten Code ist erkennbar, dass der EfPocoAdapter nicht nur die Tabellenspalten als Code abbildet, sondern auch im Datenmodel hinterlegte relationale Beziehungen abbildet.

Danach muss man sich den eigentlich, speziellen Adapter generieren mit dem die POCO Klassen via Entity Framework auf die relationalen Daten zugreifenn können. Die Kommandoezeile für diese Generierung ist folgendermassen ...

 c:\SdkSamples\EFPocoAdapter\EFPocoClassGen\bin\Debug\EFPocoClassGen.exe /incsdl:NorthwindPocoEf.csdl 
/mode:PocoAdapter 

/outputfile:NorthwindPocoAdapterClasses.cs

Damit kann man jetzt schon die Funktionalität des EfPocoAdapters nutzen. Optional kann man sich noch einen Container, zum zentralen Zugriff auf alle POCO Klassen des Datenmodells erstellen lassen. Das geht mit der Kommandozeile ...

 c:\SdkSamples\EFPocoAdapter\EFPocoClassGen\bin\Debug\EFPocoClassGen.exe 
/incsdl:NorthwindPocoEf.csdl 

/mode:PocoContainer 

/outputfile:NorthwindPocoContainerClasses.cs

Der hier erzeugte Sourcecode für POCO Klassen, den Adapter und optional für den Container muss man ebenfalls in das betreffende Projekt aufnehmen und eine Referenz auf das EfPocoAdapter Assembly setzen. Eine Referenz auf "System.Data.Entity" braucht man übrigens auch.

image

Wenn diese POCO-Klassen in eine Library verpackt werden, muss man auch im aufrufenden Assembly, z.B. Webservice- oder UI-Projekt diese beiden Referenzen setzen. In der Config Datei, die das so erstellt Assembly nutzt, muss man jetzt noch folgenden Connectionstring zur Verfügung stellen.

 

   <connectionStrings>
    <add name="NorthwindPocoEfContext" 
         connectionString="metadata=NorthwindPocoEf.csdl|NorthwindPocoEf.ssdl|NorthwindPocoEf.msl;
 providerName="System.Data.EntityClient" />
            provider=System.Data.SqlClient;provider connection string=&quot;Data Source=(local);Initial Catalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True&quot;"
  </connectionStrings>

Wichtig: Im Bereich Metadata müssen die erzeugten ".CSDL", ".SSDL" und ".MSL" Files eingetragen werden!

Und nun kann man die POCO mit Adapter zum Zugriff auf die relationalen Daten verwenden; - ungefähr so ...

        try
            {
                NorthwindPocoEfContext nwCtx = new NorthwindPocoEfContext();
                List<NorthwindPoco.Customers> lstCustomers =
                    (from c in nwCtx.Customers
                     where c.CompanyName.StartsWith(tbxCustomerName.Text)
                     select c).ToList<NorthwindPoco.Customers>();
                lvwResults.ItemsSource = lstCustomers;
                if (lstCustomers.Count > 0)
                {
                    if (!nwCtx.IsPropertyLoaded(lstCustomers[0], c => c.Orders))
                    {
                        nwCtx.LoadProperty(lstCustomers[0], c => c.Orders);
                    }
                    foreach (Orders o in lstCustomers[0].Orders)
                    {
                        System.Diagnostics.Trace.WriteLine(o.OrderID);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine(ex.ToString());
            }

 

Okay, das war mein Weg zu meinen ersten selbst erstellten POCO Adpater mit dem "Persistence Ignorance (POCO) Adapter for Entity Framework V1".

Viel Spass beim Ausprobieren ... Gunnard