Tuesday, May 11, 2010, 3:53 PM in Data
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.
3 comments
on this post
José Manuel Díaz:
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:
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:
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



