WCF RIA Services Support for EF 4.1 (and EF Code-First)

I am pleased to announce that WCF RIA Services now supports EntityFramework 4.1 (including EF Code-First). This will be added to the WCF RIA Services Toolkit, but we are releasing it today as a NuGet package.

Background

In April 2011, EntityFramework released version 4.1 of their product, which contained 2 important updates –

  1. DbContext based API
  2. Code-First support

You can get more information about the EF 4.1 release on the ADO.NET team blog. We are adding support to these 2 features in the WCF RIA Services V1.0 SP2 release. This consists of the following additions / changes –

  • A new domain service that supports DbContext and Code-First known as DbDomainService.
  • Tooling support to generate code for the custom DbDomainService, just like the LinqToEntitiesDomainService.

This will allow you to use EF DbContext in either the data first, model first or Code First modes with WCF RIA Services.

Download

Pre-requisites

    – You will need WCF RIA Services V1.0 RTM, SP1 or SP2 installed.

NuGet package – The WCF RIA Services runtime support for EF 4.1 is in the assembly Microsoft.ServiceModel.DomainServices.EntityFramework.dll. You can get it here-

RIAServices.EntityFramework NuGet Package

DbDomainService CRUD Methods Code Snippet – For the benefit of anyone trying this preview, I have put together code snippets that will generate CRUD methods for the custom DbDomainService. Please note that these code snippets will not be released/supported officially. They are there only to make the process of trying out this preview as easy as possible. You can download the code snippets here –

C# Snippet / VB Snippet

What is not included?

1. Wizard support – The wizard support for DbDomainService is embedded in the product and cannot be added until we are ready with the next release. For now, you will have to manually code a DbDomainService or use the Code Snippets provided

2. Database Initializer settings – The EF Database Initializer needs to be tweaked depending on whether the context is runtime or design-time. This logic is also in the product and not available as a part of this preview. So for this preview, you have to set the initializer manually for design-time as I explain in the walkthrough below.

Getting started

Here I will walk you through how you can get started with using EF Code-First in a WCF RIA Services App. Let us assume that you have WCF RIA Services installed. If not, you can install it from here.

1. Create a WCF RIA Services Application

Create a Silverlight Application with the Enable RIA Services option enabled or any other WCF RIA Services project (like the Silverlight Business Application).

2. Add the RiaServices.EntityFramework NuGet package to the project.

To do that, go to Package Manager Console and type “Install-Package RIAServices.EntityFramework”.

This should automatically install the EntityFramework 4.1 for you, if you don’t have it already installed. If you already have it installed, add a reference to EntityFramework.dll to the project. You will also need to add a reference to System.Data.Entity.dll.

3. Add an EntityFramework Model using the Code-First approach to the web project.

So let us define an entity called Product, with some properties on it. We will also define a  DbContext called ProductDbContext that has a DbSet of Products on it. (You can find more information on how to use EF Code-First here). So the code looks like this –

namespace EFCFSample.Web
{
    public class Product {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public int? CategoryID { get; set; }
        public Decimal? UnitPrice { get; set; }
        public bool Discontinued { get; set; }
    }

    public class ProductDbContext : DbContext {
        public ProductDbContext()
        {
            if (HttpContext.Current == null)
            {
                Database.SetInitializer<ProductDbContext>(null);
            }
        }

        public DbSet<Product> Products { get; set; }
    }
}

Notice the code I have in the ctor of the ProductDbContext? That piece of code checks if the HttpContext is null and if it is, sets the database initializer to null. Here is why we need it.

Additional Code Changes Needed to Work with the Preview –

EntityFramework initializes the database when you create a DbContext. instance. You want that to happen at runtime but not at design time. WCF RIA Services will initialize the DbContext at design time as well (only for EF Code-First). So we need to prevent the database from being initialized at design time. The logic to to do this is embedded in the product that will be released with the RIA Services V1.0 SP2.

So, until then, you will have to manually prevent the database from being initialized at design time. To do that, we identify if the execution context is design time context (by checking if the HttpContext.Current is null) and if it is, we set the database initializer to null. Note that this will not be required with the actual release bits of WCF RIA Services V1.0 SP2 and Toolkit.

4. Add a DbDomainService.

Alright, now that the DbContext has been set up, we can go ahead and define a class deriving from DbDomainService<ProductDbContext> (similar to any other RIA Services DomainService) like this –

namespace EFCFSample.Web
{
    [EnableClientAccess]
    public class DomainService1 : DbDomainService<ProductDbContext>
    {
    }
}

5. Add CRUD Methods to the DbDomainService

Now, we will use the C# code snippet to generate the CRUD methods for us. So download the code snippet to the disk. Then use the VS Code Snippet Manager to import it to Visual Studio. For more information on how to do that, refer to this msdn documentation. I would recommend importing it to My Code Snippets (which will be typically under c:\Users\<username>\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets)

When that is done, from within the class declaration, use the shortcut “dbcrud” to get your DbDomainService CRUD methods defined for you.

Note that this code snippet has 3 variables that you need to supply –

  1. Name of the Entity (in this case, Product)
  2. Name of the DbSet property corresponding to the entity (Products)
  3. Name of the entity (this is used to generate the names of the CRUD methods – like GetProducts, etc.).

So our DbDomainService looks like this-

namespace EFCFSample.Web
{
    [EnableClientAccess]
    public class DomainService1 : DbDomainService<ProductDbContext>
    {
        public IQueryable<Product> GetProducts()
        {
            return this.DbContext.Products;
        }

        public void InsertProduct(Product entity)
        {
            DbEntityEntry<Product> entityEntry = this.DbContext.Entry(entity);
            if ((entityEntry.State != EntityState.Detached))
            {
                entityEntry.State = EntityState.Added;
            }
            else {
                this.DbContext.Products.Add(entity);
            }
        }

        public void UpdateProduct(Product currentProduct)
        {
            this.DbContext.Products.AttachAsModified(currentProduct, this.ChangeSet.GetOriginal(currentProduct), this.DbContext);
        }

        public void DeleteProduct(Product entity)
        {
            DbEntityEntry<Product> entityEntry = this.DbContext.Entry(entity);
            if ((entityEntry.State != EntityState.Deleted))
            {
                entityEntry.State = EntityState.Deleted;
            }
            else {
                this.DbContext.Products.Attach(entity);
                this.DbContext.Products.Remove(entity);
            }
        }

    }
}

Again, the SP2 release bits will have full wizard support for DbContext. So you should not need to do any of this dance with the code snippet. But till then, this should be easy enough for you to do.

5. Use the DbDomainService in your App

With this, you have a RIA Services DomainService talking to a EF Code-First database that you can use, just like in any other RIA Services application. Of course, you can add/modify the methods in the generated DomainService or add more CRUD methods for other entities in your EF Model.

In short, your EF Code-First model is ready for use in the WCF RIA Services app! 

If you are interested in trying using EF Code-First or simply DbContext with WCF RIA Services, try out this preview and let us know how you find it. Any feedback from you will be highly appreciated!