Entity Framework 4.0 POCO Classes and Data Services

If you've flipped on the POCO (Plain Ol' CLR Objects) code generation T4 templates for Entity Framework to enable testing or just 'cuz you like the code better, you might find that you lack the ability to expose that same model via Data Services as OData (Open Data). If you surf to the feed, you'll likely see something like this:

The XML page cannot be displayed

Cannot view XML input using XSL style sheet. Please correct the error and then click the Refresh button, or try again later.


The following tags were not closed: feed. Error processing resource 'http://localhost:10749/MyODataEndpoint.svc/Posts'

 

There are two problems. The first problem is that we're not reporting the problem very well. You can't see what's happening in IE8 with a simple View Source, as apparently IE won't show malformed XML. Instead, you have to use Fiddler or some other tool (I'm a big tcpTrace fan) to see the actual error in the HTTP response:

 

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed ...>
<title type="text">Posts</title>
<id>http://localhost:8080/MyODataEndpoint.svc/Posts</id>
<updated>2010-05-11T22:48:13Z</updated>
<link rel="self" title="Posts" href="Posts" />
<m:error>
<m:code></m:code>
<m:message xml:lang="en-US">Internal Server Error. The type
'System.Data.Entity.DynamicProxies.Post_CF2ABE5AD0B93AE51D470C9FDFD72E780956A6FD7294E0B4205C6324E1053422'
is not a complex type or an entity type.</m:message>
</m:error>

 

It's in the creation of the OData feed that the error happens, so instead of clearing the response and just returning the error, we dump it into the middle of the output, making it very difficult to find. In this case, what we're telling you is that you've mistakenly left dynamic proxy creation on, which doesn't work with EF4 POCO objects and Data Services in .NET 4.0. To fix this, you need to override the CreateDataSource method in your DataService<T> derived class:

 
public class MyODataEndpoint : DataService<FooEntities> {
  public static void InitializeService(DataServiceConfiguration config) {
    ...
  }

  protected override sellsbrothersEntities CreateDataSource() {
    var dataSource = new FooEntities();
    dataSource.ContextOptions.ProxyCreationEnabled = false;
    return dataSource;
  }
}

 

This solution came from Shyam Pather, a Dev Manager on the EF team. He says that once you turn off proxy generation, you give up lazy loading and "immediate" change tracking. Instead, you'll get "snapshot" change tracking, which means the context won't be informed when the properites are changed, but the context still detects changes when you call DetectChanges() or SaveChanges(). For the internals of a Data Service, none of this matters, but any code you write in query interceptors, change interceptors, or service operations will have to be aware of this.

This limitations are only true when used from the OData endpoint, of course. The rest of your app will get proxy creation by default unless you turn it off.



Comment Feed 3 comments on this post

José Manuel Díaz:


Hi,

I'm looking for a pattern to provide custom business logic in an Entity Framework + WCF Data Services.

From the standard solutions I've seen documented (POCOs, Interceptors, Service Operations), I've decided to use POCOs because I want a lot of flexibility.

I've already succeded in tuning the oficial T4 template for generating POCOs to expose two classes per entity (VB):

    Partial Public Class Entity1
        Inherits Entity1ImplementationBase
    End Class

    Public Class Entity1ImplementationBase
        'Model fields:
        Public Overridable Property Field1 As String
    End Class

Then, I can provide custom read logic in a separate file:

    Partial Public Class Entity1
        Public Overrides Property Field1 As String
            Get
                'Override read logic here.
            End Get
            ...
        End Property
    End Class

I haven't studied the write scenario yet.

The problem is that I want to provide fields other than database columns, i.e., I want to provide code computed fields that trigger custom logic in read and write scenarios. For example, a field that triggers a query to a cache or to an external system (both for reading and writing).

When I add such a field to my POCO, it is not exposed in the WCF Data Service. The service only expose the fields in the conceptual model, and they can only be database columns.

I've not tuned the context generation template, so it generates a class that inherits ObjectContext. And the DataService uses that type for generic instantiation.

Is there a simple way to do what I want?
I'm studying the Reflection Provider and Custom Provider capabilities, but I imagined there had to be a simpler way to achieve a mixed database + custom logic service composition.

Thank you very much.

Best regards,
José Manuel

Monday, Dec 13, 2010, 9:42 AM


Rob de Bruin:


Thanks, your post has helped me create my first OData service :)
I had to use slightly different code tough:
        protected override MyDbContext CreateDataSource()
        {
            var ds = base.CreateDataSource();

            ds.Configuration.ProxyCreationEnabled = false;

            return ds;
        }
must be because I'm using EF 4.1.0.0

Friday, Oct 7, 2011, 1:17 AM


John Parr:


Has anyone here successfully used stored procedures with DbContext T4 template together with WCF Data Services?

I have tried both DbContext and POCO Generators and while the service work normally I get this for my stored procedure that are imported into the model I am still receiving the error

Any help would be appreciated

Thursday, Nov 3, 2011, 5:42 AM





comment on this post

HTML tags will be escaped.

Powered By ASP.NET

Hosted by SecureWebs

Mensa

IEEE


moving companies
sunglasses
Kratom
How To Lose Weight Fast
Play Bingo Online
Comcast Xfinity Internet
Online Payroll Services