More with the Entity Framework V6 RC1

Introduction

In my last post, I explained how to add a NuGet package to a solution, and from there how to generate and lightly consume an Entity Framework data model.  We’re going to take it to the next level now, and do a bit more with the framework.

Expanding on the Solution

Since we had a tiny bit of read functionality in the last post, I’m going to build upon that functionality and introduce concepts we’ll need as we start to factor in layers – particularly service boundaries.  Luckily for us the latest version of the Entity Framework gives you one super-massive benefit over earlier versions: the entities are defined as Plain Old CLR Objects (POCO) out-of-the-box!

What are POCO objects?

Well, we should really say “what are POCOs?”, since the “O” stands for “Object”.  That said, POCO classes are basic class definitions with properties and little else.  They are intended to represent basic data entities, with little else.

The main benefit is that they aren’t tied to any persistence implementation (i.e. scaffolding which handles the object’s persistence to a data store) which means the objects can be passed around and consumed without the risk of corrupting the data.

Here’s an example from the data model we generated in the last article:

namespace RSPhotography.DataAccess
{
    using System;
    using System.Collections.Generic;
    
    public partial class Genre
    {
        public Genre()
        {
            this.ChildGenres = new HashSet<Genre>();
            this.Catalogs = new HashSet<Catalog>();
        }
    
        public int GenreId { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public Nullable<int> ParentGenreId { get; set; }
    
        public virtual ICollection<Genre> ChildGenres { get; set; }
        public virtual Genre ParentGenre { get; set; }
        public virtual ICollection<Catalog> Catalogs { get; set; }
    }
}

 

Note that this example still has some more “complex” structure to it – namely the self join “navigation properties” which are correctly modelled as either a parent instance, or a collection of child elements.

These classes are generated by T4-templates which are shipped as part of the Entity Framework supporting files.  When you update the DB model, these files are automatically updated to reflect schema changes.  Nifty.

You can extend these classes by placing an implementation side-by-side within the same assembly, which is a handy way to define static properties which are not blown away when the model is updated.  If you have the need for properties which are common to your entity classes, you can also specify a base class, but opening the data model and setting the class in the properties window:

image

I’ll come back to this in a future article.

Give me an example of why POCO objects are useful!

OK, fair enough.  It might not look like much of a drawcard, so I’ll demonstrate the usefulness by showing how the model can be exposed in a more real world kind of fashion.  So, you’ll recall we have a data access assembly which contains classes.

Within this assembly is a data accessor for data contained within the Catalog table, let’s expand on that class first.  I’m going to add a more useful implementation, like so:

public ReadOnlyCollection<Catalog> FindItemsByLocation(Location loc) { if (loc.LocationId <= 0 || loc.RegionId <= 0) { throw new ArgumentException("LocationId or RegionId

must be specified"); } _context.Configuration.LazyLoadingEnabled = false; IQueryable<Catalog> query = (from a in _context.Catalogs select a); if (loc.LocationId > 0) { query = query.Where(x => x.Locations.Any(

y => y.LocationId == loc.LocationId)); } if (loc.RegionId > 0) { query = query.Where(x => x.Locations.Any(

y => y.RegionId == loc.RegionId)); } return query.ToList().AsReadOnly(); }

 

If going to explain this implementation in a little more detail.

  • First off, there’s some basic argument checks, to ensure something is being passed in to actually filter the data. 
  • Next, I’m setting “Lazy Loading” to false – which means that the returned entities will be disconnected from the data context.  More on that later.
  • Now I use something called an IQueryable to build up my actual data query, I establish the base query first
  • Then I filter based on the arguments to ensure the parameters are applied as “WHERE” clauses
  • When I’m done, the last step is to execute the query, calling .ToList() on the IQueryable variable

So I’ve updated my unit tests and added a new one which invokes this new data access method.  Let’s take a look at the impact of Lazy Loading, which I mentioned above.

Lazy Loading

Lazy loading is akin to “just read related data on demand”, and means that after the initial query, accessing a property or collection of an object will cause the database to be subsequently queried at runtime.  Here’s a visual difference:

Lazy Loading Enabled:

image

Lazy Loading Disabled:

image

Notice the difference?  You can expand the properties and collections when lazy loading is enabled, but not when it is disabled – we prefer the latter experience when dealing with service boundaries, where we want to return all relevant data at once.

What is an Object Graph?

This was posed to me late last year, and I thought it was commonly known.  An object graph is a complex collection of related instance objects.  When you deal with more complex data structures, this becomes important, because you need to factor in how big they can get.

We’ll be bumping into this term a lot in this article – you’ve been warned Smile

Now let’s introduce a WCF service application so that I can demonstrate the differences when you start exposing your Entity Framework entities to the wire.

Add a WCF Service Application

In your solution explorer add a new WCF Service Application, as illustrated below:

image image

I’m going to rename the default service to something more meaningful.  You can do this by renaming the files, and also by inline refactoring.

image

At this point, don’t forget to Update the Web.Config so that it includes the relevant Entity Framework configuration.  It’s easiest to open the App.Config from the data access assembly and the web.config horizontally.  Copy the config into the top of the web.config, just below the <configuration> node.

image

Add a project reference to the Data Access assembly, and then build some service plumbing.  Here’s mine, remembering to write the service interface first:

using RSPhotography.DataAccess;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RSPhotography.WebServices
{    
    [ServiceContract]
    public interface ICatalogService
    {

        [OperationContract]
        ReadOnlyCollection<Catalog> GetCatalogByLocation(Location value);
    }
}

 

 

using RSPhotography.DataAccess; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; namespace RSPhotography.WebServices { public class CatalogService : ICatalogService { public ReadOnlyCollection<Catalog> GetCatalogByLocation

(Location value) { try { using (CatalogDataAccessor accessor =

new CatalogDataAccessor()) { return accessor.FindItemsByLocation(value); } } catch (Exception ex) { Trace.WriteLine(ex.Message); } return null; } } }

 

So far so good.  If you’ve done all this and can compile, you’re heading in the right direction.  However, WCF introduces a whole new set of complexity as you’re about to find out.  To make sure everything’s OK, right click on the .svc file in Solution Explorer and select “View in Browser (name of your default browser)” and just make sure the service resolves:

image

Note that, by default, the project will use  IIS Express.

Adding another Unit Test project

The next step is to add a brand new Unit Test project and add a service reference to the newly minted WCF service.  You can just “Discover” the service once you have the Add Service Reference dialog open.  I Called it “ServiceReference” for brevity.

image

So here’s my unit test:

[TestMethod]
public void TestService()
{
    using (CatalogServiceClient c = new CatalogServiceClient())
    {
        Location loc = new Location();
        loc.LocationId = 1;
        var result = c.GetCatalogByLocation(loc);
        Assert.IsTrue(result.Count > 0, "Should be at least one record");
        Trace.WriteLine(result[0].Title);
    }
}

All pretty straightforward, hopefully.  Here’s where things go pear shaped.  If you’ve followed along, you’ll find I’ve led you down the garden path – on purpose.  I want to introduce you to some WCF debugging and analysis because, believe me, you’re going to need to know this.

Important: Determining the cause of WCF issues

Upon executing the Unit Test, we receive this ugly and unhelpful exception:

image

“A first chance exception of type ‘System.ServiceModel.CommunicationException’ occurred in mscorlib.dll” – which is pretty generic and extremely unhelpful.

So at this point, you might diligently head over to your WCF application’s Web.Config file and change the following:

<behaviors>
    <serviceBehaviors>
        <behavior>
            <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
    </serviceBehaviors>
</behaviors>

 

However, this won’t help.  What you need to do is enable tracing for the WCF service, which you can do manually in the service application’s Web.config.  However, doing this by hand is tedious – there’s a better way!

In Visual Studio, go to Tools –> WCF Service Configuration Editor.  Once it loads, browse to your Web.config, and then expand the “Diagnostics” node.  You can see the options, click to enable tracing.

image

Save and exit, and return to Visual Studio.  If you re-run the same unit test now, it will generate a service trace log in the location indicated in the config file.  If you browse to that location and double click on the trace file it should open in the WCF tracing tool.

Under “Activity” any issues will be in red text.  Double click on the red text and scan for exceptions:

image

As you can see from the below image, there has been an exception thrown:

image

This screen gives us the actual exception information:

Type 'System.Data.Entity.DynamicProxies. Catalog_1F5B5519A0772307B45546CB10E51B38AA4E82B656391DE726FA25F2B3B8A8B5' with data contract name

'Catalog_1F5B5519A0772307B45546CB10E51B38AA4E82B656391DE726FA25F2B3B8A8B5: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies'

is not expected. Consider using a DataContractResolver or add any types not known

statically to the list of known types - for example, by using

the KnownTypeAttribute attribute or by adding them to the list of

known types passed to DataContractSerializer.

 

The secret is that in our data access class, you need to ensure that when Entity Framework entities are created, that the EF proxy creation is off, as WCF can  not handle non-static (that is, dynamic) types.

_context.Configuration.ProxyCreationEnabled = false;

 

Once you have applied this change and recompiled, there’s a good chance your test will succeed:

image

But wait – there’s more: Include()

So now we’re getting back a collection of results – exciting – but there’s one tiny problem when you look closely:

image

None of the related entities are returning.  That’s right, we’re extracting the base entities just fine, but the query doesn’t walk the object graph.  In the Entity Framework, when you query, you have to explicitly name “paths” to include in the query – particularly if you aren’t using lazy loading, as the query won’t automatically include all navigation properties.

To explicitly include a navigation property you have to specify it in an include directive, such as the below:

IQueryable<Catalog> query = (from a in _context.Catalogs.Include("Locations")
                             select a);

 

This forces the inclusion of one of the FK/collections we’re interested in.  Returning to the first unit test project we created, we can observe it working:

image

To extend the object graph to include other navigation properties, we add more to the “.Include()” directives – but use this sparingly!  It is not recommended to use more than two or three inclusions per query, due to the vast amount of data it will could suck into your object graph.

IQueryable<Catalog> query = (from a in _context.Catalogs
                                    .Include("Locations")
                                    .Include("Genres")
                                    .Include("Sizes")
                             select a);

 

Now that we have that cleared up, you’d think we’re right as rain?  Not quite, the same sort of unit test through the WCF service implementation throws an exception:

image

It’s our unfriendly CommunicationException!  Switching to the WCF trace, we can quickly find the culprit.

There was an error while trying to serialize parameter http://tempuri.org/:GetCatalogByLocationResult. The InnerException message was ‘Object graph for type ‘System.Collections.Generic.HashSet`1[[RSPhotography.DataAccess.Location, RSPhotography.DataAccess, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]’ contains cycles and cannot be serialized if reference tracking is disabled.’.  Please see InnerException for more details.”

It’s my old nemesis, the cyclic redundancy issue.  Because the Location table has a “self-join”, WCF complains about a potential issue if entities became self-referential, it could cause an infinite loop of sorts.  That’s kind of funny, because you’d think it would be more of an Entity Framework problem than a service level issue.

(Sort of) Solving the WCF Object Graph/Cycle Issue

Well, I’m working through this one step at a time – and I have prior experience with this particular issue way back in 2010 – however, at the moment the solution which at least works for reading data is fairly straightforward.

Could it be this simple?  Honestly, I hope so.. it seems that the key is to decorate each class with the following attribute:

  [DataContract(IsReference=true)]

 

Now obviously, we don’t want to spend too much time and effort on decorating each entity (you might have lots), so there’s a faster way to make this happen, and I alluded to it earlier in this post: base classes.

Adding a Base Class for your Entities

Create a new class in the same project as your EF entities.  It can be very simple, like mine:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace RSPhotography.DataAccess
{
    [DataContract(IsReference = true)]
    public partial class EntityBase
    {
    }
}

 

Heading back to Solution Explorer, if you expand the <Model>.edmx, locate the Model.tt file.  Right click and select “Open With” and pick XML (Text) Editor.

image

Locating the placeholder for the class definition, you can add the declaration to inherit from a base class, like so:

<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
<#=codeStringGenerator.EntityClassOpening(entity)#> : EntityBase
  {

 

This will mean that all of your entity classes will derive from this common base class.  Rebuilding will cause the T4 template to regenerate the entity class definitions.  Don’t forget to rebuild everything, and refresh your service reference in the service unit test project!

Re-running the same unit test from before shows us:

image

Now you might expect problems on the client side, but it appears that the client generated classes (attached to the Service Reference) in the web service unit test includes both the base class definition, and the attribute necessary to avoid the cyclic graph issue:

image

Just to be sure, I added a service method to the service and passed a Catalog entity back – and it worked, no issues.  So much easier than before!

Summary

So there’s been a lot to cover off in this article.  It’s a work in progress at this stage, but we’ve accomplished quite a bit.  Let’s recap – we:

  • Reviewed POCO objects and their purpose,
  • We discussed lazy loading, and disabled it for transfer via WCF,
  • We looked at proxy classes and why they don’t work with WCF,
  • We established how to enable WCF tracing,
  • We used the WCF Configuration Tool and Trace Tool to locate the cause of exceptions,
  • Lastly, we edited the T4 template to establish a base class for all EF POCO classes

That’s probably a good place to finish up on for now.

Here’ the updated solution [ Solution Files ]

A note about the sample – you’ll have to re-add the Entity Framework NuGet package as I excluded it for license and file size reasons.  Fastest way is to delete the entry in one of the project’s packages.config file and then re-add through the NuGet package manager.

If anyone has a more elegant solution to establishing the DataContract attribute on entity classes (without hard coding it into the T4 template), I’d be keen to hear.

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 thoughts on “More with the Entity Framework V6 RC1”