Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

POCO Entities Through RIA Services

0.00/5 (No votes)
10 Dec 2010 1  
This article demonstrates how to generate plain old class objects (POCO) from the Entity Framework v4 (EF4) and use them through RIA Services in SilverLight version 4.

Introduction

The point of using plain old class objects (POCO) is to abstract your data from the Entity Framework v4 (EF4) .edmx files for the purposes of portability, testing, data security, data validation, and providing data services; further abstraction is placing the POCO classes in a DLL separate from the EDMX file. This article does just that by demonstrating how to generate plain old class objects (POCO) using the .tt file plus .tt file (T4) generator and then pass these data context unaware POCOs through RIA Services SP1 Beta into Silverlight v4. For this example, you must have the following installed:

Also, you must have a database source that you will be connecting to; I am using SQL Server but you can use whatever.

Background

Microsoft does not make this easy - there is very little support or documentation for using POCO entities disconnected from the EDMX (i.e. in a separate DLL) with T4, EF4 and RIA services because the technology is so new. In fact, those poor people who implemented EF3.5 and an earlier version of RIA services will find that it has changed somewhat dramatically.

Connecting to Your Database

  1. Click File, New Project from inside of Visual Studio. You are going to select the project template ASP.NET Dynamic Data Entities Web Application. If you do not see this template, click Other Languages and select Visual C#. Use the information below:
    • Project name: BasicDataViewer
      • Type: ASP.NET Dynamic Data Entities Web Application
      • Purpose: This project is where your EDMX file is stored and can display SQL Server, or Oracle or whatever EF4 generated entity in a website so that you can confirm your complex relationships.
  2. Right-click on your new project BasicDataViewer and select Add, New Item. You are going to add an ADO.NET Entity Data Model which can be found under the Visual C#, Data templates directory.
    • Project name: BasicDataViewer
    • Item name: DBData
      • Type: ADO.NET Entity Data Model
      • Purpose: This item will help you to create an entity model to logically map to your database (mapping is done automatically by EF4 when you save the .edmx).
  3. When you click OK, you will want to follow through the wizard in order to connect to your data source. Select 'Generate from database' and create a new connection. Check Save your connection settings to your Web.Config (it is a checkbox at the bottom of the Entity Data Model Wizard in the second step). In the third step of the wizard, you are going to choose which database tables to include in your model. When you click okay, it should create a basic outline of your model.
  4. In the .edmx editor, right-click on a blank space where there are no tables or associations being displayed and select Properties. You are going to change the following properties on your .edmx:
    • Metadata Artifact Processing = Copy to Output Directory
    • Namespace = DBDataModel
    • Entity Container Name = DBData
  5. After rebuilding the solution, edit your web.config file and update the following setting (uncomment this line if is commented in the web.config).
    DefaultModel.RegisterContext(typeof(DBData), 
    	new ContextConfiguration() { ScaffoldAllTables = false });
  6. Press F5 to build and debug your project. It should display your data in a website with the relationships. If it does not or there are errors, you will need to work through them (old databases might complain about allowing null characters, in which case search for the field; you may need to edit the backend of your .edmx to set nullable="true").

Creating the POCO DLL using T4 (POCO Entity Generator)

  1. In the .edmx editor from BasicDataViewer project created previously, right-click on a blank space where there are no tables or associations being displayed and select Add Code Generated Item. You are going to create an ADO.NET POCO Entity Generator under Visual C# template types.
    • Project name: BasicDataViewer
    • Item name: DBDataModelPOCO
      • Type: ADO.NET POCO Entity Generator
      • Purpose: This item will generate T4 files which will create your POCO entities. It should add two items in the project called DBDataModelPOCO.Context.tt and DBDataModelPOCO.tt
  2. Create a new Class Library project in your solution (File, Add, New Project). Delete Class1.cs if it is created automatically.
    • Project name: Entities
      • Type: Class Library
      • Purpose: This project will contain our POCO entities as well as validation, key attributes and perhaps basic business logic.
  3. Add reference to the framework assembly System.Data.Entity by right-clicking on the Entities project and selecting Add Reference.
  4. While holding down the <SHIFT> key click and drag the DBDataModelPOCO.Context.tt and DBDataModelPOCO.tt files from the BasicDataViewer project to the Entities project. You will notice that there are classes under the .tt files that are autogenerated.
  5. Double-click on each .tt file to edit them; you will be changing the location of the .edmx so that it knows how to build the classes:
    string inputFile = @"..\BasicDataViewer\DBData.edmx"; 
  6. Next, right-click on each of your .tt files and select Run Custom Tool; this will recreate your POCO entities and confirm the connection to your .edmx.
  7. Build the Entities class library project by right-clicking on it and selecting the Build option.
  8. Add a reference to the Entities project in the BasicDataViewer project by right-clicking on the BasicDataViewer project and selecting Add Reference, Projects tab, Entities.
  9. Edit the BasicDataViewer web.config file and update the following setting:
    DefaultModel.RegisterContext(typeof(Entities.DBData), 
    	new ContextConfiguration() { ScaffoldAllTables = true});
  10. Finally, press F5 to build your project and test your POCO entities are being accessed correctly. If there are errors, you may need to work through them. I did not encounter any at this point.

Accessing the POCO Entities in Silverlight Using RIA Services

  1. Add a reference to System.Componentmodel.DataAnnotation in the Entities project by right-clicking on the project and selecting Add Reference.
  2. The classes that need to be updated in step 3 are going to vary for you based on what tables you have setup in your .emdx file. It is easy to determine which classes to update by double-clicking on them under the .tt files and looking for primitive properties. Don't worry too much about getting this wrong, the compiler will complain that you have no keys for a particular class if you do not set this up correctly. Here is my structure, I only have one class called Zip.cs:
    • DBDataModelPOCO.Context.tt
      • DBDatamodelPOCO.Context.cs
    • DBDataModelPOCO.tt
      • DBDataModelPOCO.cs
      • Zip.cs
  3. For all non-complex types, you will need to also define keys and metadata. In this example, I am only accessing one table called Zip. So, I edit the Zip.cs under DBDataModelPOCO.tt to include metadata and key attributes. This metadata is where you would have your validation and business logic. These metadata classes should be broken out into a separate file and referenced in the Zip class MetadataTypeAttribute attribute, but I have placed them as internal classes so you can understand that they are 'buddies':
    //------------------------------------------------------------------------------
    // <auto-generated>
    //     This code was generated from a template.
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
     
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    // ********** You are going to add this
    using System.ComponentModel.DataAnnotations;
     
    namespace Entities
    {
        // ********** You are going to add this
        [MetadataTypeAttribute(typeof(Entities.Zip.ZipMetadata))]
        public partial class Zip
        {
     
            // I created this internal class right here so that RIA can use the class
            internal sealed class ZipMetadata
            {
                private ZipMetadata()
                {
                }
     
                // I created this key class right here so that RIA can use the class
                [Key]
                public string ZipCode { get; set; } 
            } 
     
            #region Primitive Properties
        
            public virtual string ZipCode
            {
                get;
                set;
            }
        
            public virtual string City
            {
                get;
                set;
            }
        
            public virtual string County
            {
                get;
                set;
            }
        
            public virtual string State
            {
                get;
                set;
            }
        
            public virtual decimal TaxRate
            {
                get;
                set;
            }
        
            public virtual byte[] tstamp
            {
                get;
                set;
            }
     
            #endregion
        }
    }
  4. Next, we are going to add a WCF RIA Services Class Library project to our solution. Do this by right-clicking on your solution and selecting add project. Then select WCF RIA Services Class Library from under the Silverlight templates.
    • Project Name: EntRIAServices
      • Type: WCF RIA Services Class Library
      • Purpose: This provides RIA services to your Silverlight application. It will create two sub-projects, the one we are interested in has a .Web extension and should be called EntRIAServices.Web; the other sub-project is called EntRIAServices.
        • EntRIAServices ~ This is the main project
          • EntRIAServices ~ This is a sub-project
          • EntRIAServices.Web ~ This is a sub-project
  5. Delete the Class1.cs file that is automatically created in both sub-projects.
  6. Add reference to the framework assembly System.Data.Entity by right-clicking on the EntRIAServies.Web sub-project and selecting Add Reference.
  7. Add reference to the Entities project by right-clicking on the EntRIAServies.Web sub-project and selecting Add Reference.
  8. Rebuild the entire solution and check for errors. Any errors you encounter here should be related to step 3.
  9. Add a Domain Service Class to the EntRIAServices.Web sub-project called EntityDomainService. Do this by right- clicking on the EntRIAServices.Web sub-project and selecting Add, New Item, Domain Service Class. In the Add New Domain Service screen that appears, be sure to select <Empty Domain Service Class> under Available DataContext/ObjectContext classes and that Enable Client Access is checked.
    • Project Name: EntRIAServices.Web
    • Item Name: EntityDomainService
      • Type: Domain Service Class
      • Purpose: This is basically the WCF part of RIA services; it is the code generator for your service, I have no idea why Microsoft called it this. We are creating an empty Domain Service because we are not using Linq (we have our entities).
  10. Now that we have our RIA Services code generator, we are going to add access points to it. This can be done by creating an iQueryable, Invoke or IEnumberable interface, please see my notes below on how to get the correct connection string. Most of the errors I encountered here were related to referencing the metadata, which is a set of three files (csdl, msl, ssdl) created by our .edmx file (property Metadata Artifact Processing = Copy to Output) on save that serve to define your database's structure as it relates to your POCO entities; it would be nice to embed these as a resource.
    namespace EntRIAServices.Web
    {
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.ComponentModel.DataAnnotations;
        using System.Linq;
        using System.ServiceModel.DomainServices.Hosting;
        using System.ServiceModel.DomainServices.Server;
     
     
        // TODO: Create methods containing your application logic.
        [EnableClientAccess()]
        public class EntityDomainService : DomainService
        {
     
            // For this I copied the connection string from the 
            // web.config file of the BasicDataViewer file
            // (i.e. it's where by .EDMX file is located and the 
            // .EDMX generated it for me because I selected 
            // Save your connection settings to your Web.config when I created it)
            // I had to modify it to point to the physical location of the 
            // metadata files generated by my 
            // .EDMX also, I changed the escape characters to single quotes
            // after selecting the Metadata Artifact property to 
    
            //"Copy to Output Directory"
            private Entities.DBData _context = new Entities.DBData
    	("metadata=C:\\Users\\Owner\\Documents\\Visual Studio 2010\\
    	Projects\\BasicDataViewer\\BasicDataViewer\\bin\\DBData.csdl|C:\\
    	Users\\Owner\\Documents\\Visual Studio 2010\\Projects\\
    	BasicDataViewer\\BasicDataViewer\\bin\\DBData.ssdl|C:\\Users\\
    	Owner\\Documents\\Visual Studio 2010\\Projects\\BasicDataViewer\\
    	BasicDataViewer\\bin\\DBData.msl;provider=System.Data.SqlClient;
    	provider connection string='Data Source=SERVER\\DB_NAME;
    	Initial Catalog=YOUR_DATABASE_NAME;User ID=YOUR_DB_LOGIN;
    	Password=YOUR_DB_PWD;MultipleActiveResultSets=True'");
    
            [Query]
            public IQueryable GetZips()
            {
                return (IQueryable)_context.Zips.AsQueryable();
            }
        }
    }
  11. Rebuild the entire solution, this will create a hidden folder under the EntRIAServices sub-project called Generated_Code which is your RIA Services connection. You can ignore this or check it out to make sure it is there by showing all files on this sub-project. If it is not there on build, something went wrong and you will need to retrace your steps.
  12. Now we are going to add a SilverLight Business Application project to our solution to consume our RIA Services. You can do this by right-clicking on your solution and selecting Add, New Project, and choosing SilverLight Business Application under the Silverlight installed templates.
    • Project Name: BusinessApplication1
      • Type: Silverlight Business Application
      • Purpose: Consume RIA Services and enable data edits via a user interface
  13. Step 12 will create two projects, one called BusinessApplication1 and another project called BusinessApplication1.Web. You are going to reference the EntRIAServices project in the BusinessApplication1 project by right-clicking on BusinessApplication1 and selecting Add, Add Reference. Also, you will need to reference the EntRIAServices.Web project in the BusinessApplication1.Web project by right-clicking on BusinessApplication1.Web and selecting Add, Reference.
  14. Rebuild the entire solution, twice. All errors should go away as code is generated to backup your RIA Service.
  15. Double-click on the MainPage.xaml of the BusinessApplication1 project. This will bring up the Silverlight UI editor. Now, click Data, Show Data Sources. Okay, your entity connection should appear with all of the items. Click and drag it to the UI workspace. This should create a grid of the POCO entity object on the Silverlight workspace.
  16. Press F5 to build and run the solution. It should display a grid with your POCOs populated from the database. If it does not display or you get Not Found errors, make sure that you are not trying to return too many records (504 error) and that your RIA services Generated_Code hidden folder is in the EntRIAServices sub-project (500 error). Should this not be the problem and you cannot figure out the RIA error, try using Fiddler2.

Creating a Domain Service Factory to Host POCO Entities

You will need to create a domain service factory to host your POCO entities correctly. A problem arises with using POCOs, which is that you must include relationships through Linq while hosting the data. Microsoft wrote an article on sharing entities using the Include statement, but it does not work with POCOs because they should be context unaware. Also, as is often the case, you might want to join two .edmx files or provide some highly customized business relationship between your entities or you might even want to do user access checks before providing data.

Please see the comments below and my associated article on Creating a Domain Service Factory to Host POCO Entities.

Conclusion

Here is a sample of this solution, you will need to use 7Zip to extract these files because of the high rate of compression:

Creating a POCO entity model from an .edmx entity model of a database model which is a model of your application data services in order to have RIA Services model it for your Silverlight application is killer overhead just to perform a little create, read, update and delete (CRUD) but I always felt the same about the MVVM structure because it makes changing the underlying database a chore.

Free Image Hosting

If you want my opinion of RIA Services: it is too complex to setup for what it does and I found it error prone; however, at the same time once you have the six projects setup I can see it being very powerful in terms of being able to "quickly" model and host a logical database. It would be much easier if I could just check an attribute on my .edmx to use POCOs when I deploy the project, and the related business logic was somehow tied to the visible model. Anyhow, I wish I could help all of you out there beating on your keyboards trying to work through RIA Services and EF4, but that is not possible so I hope this article helps instead.

Sincerely,
Joseph Wykel, M.B.A., M.E., B.A.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here