The only way that my WCF service can return classes from a code first model is by setting the ProxyCreationEnable
to false
using the code below.
((IObjectContextAdapter)MyDb).ObjectContext.ContextOptions.ProxyCreationEnable = false;
What are the negative consequences of doing this? One gain is that I can at least get these dynamic types serialized so they can be sent over the wire using WCF.
If DbContext.Configuration.ProxyCreationEnabled
is set to false
, DbContext will not load child objects for some parent object unless Include
method is called on parent object. Setting DbContext.Configuration.LazyLoadingEnabled
to true
or false
will have no impact on its behaviours.
If DbContext.Configuration.ProxyCreationEnabled
is set to true
, child objects will be loaded automatically, and DbContext.Configuration.LazyLoadingEnabled
value will control when child objects are loaded.
Dynamic proxies are used for change tracking and lazy loading. When WCF tries to serialize object, related context is usually closed and disposed but serialization of navigation properties will automatically trigger lazy loading (on closed context) => exception.
If you turn off lazy loading you will need to use eager loading for all navigation properties you want to use (Include on ObjectQuery). Tracking changes doesn't work over WCF it works only for modification of entity which is attached to ObjectContext.
When you use EF, it creates a proxy by default for your class. A solution can be to add this line in the constructor of your DbContext class. Your data model inherited from the DbContext class, so you can edit your model like this:
public yourDataModelEntities()
: base("name=yourDataModelEntities")
{
base.Configuration.ProxyCreationEnabled = false;
}
This class is in your EF.edmx
then in the yourmodel.Context.tt
then yourmodel.Context.cs
(Using Visual Studio 2013 or later)
To avoid the edit of the class constructor in your EF model every time you refresh the model from the database, or some other way trigger the rebuild of the code, the proper place to do the change is in the T4 code file that is responsible of actually creating the model code. I had some other issue with dynamic properties a few years back when I understood the underlying mechanics of how the classes and properties was actually created. T4!!! What a miracle it is :-D T4 syntax can be a bit intimidating at first, so reading up on the syntax is wise. Being VERY focused when making changes is also a good idea :-)
So! If you look in your model, you have a .tt file under your .edmx file. This .tt (T4) file is the script that actually creates your model class. The script will be run automatically each time you build your model or make some changes in the model editor.
Let's say your Model descriptor is named Model1.edmx. You will have a file named Model1.Context.tt in the tree under it. You will also see a Model1.Context.cs file. This is obviously the actual code file for your context. But this file is the result of the .tt script file being run! It is completely dynamically created. So no idea editing it.
Open the .tt file and you will see something like:
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF6.Utility.CS.ttinclude"#><#@
output extension=".cs"#><#
const string inputFile = @"Model1.edmx";
var textTransform = DynamicTextTransformation.Create(this);
..
..
Another 50 or so lines down, the constructor code is being scripted.
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
<#
if (container.FunctionImports.Any())
{
#>
using System.Data.Entity.Core.Objects;
using System.Linq;
<#
}
#>
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
public <#=code.Escape(container)#>()
: base("name=<#=container.Name#>")
{
base.Configuration.ProxyCreationEnabled = false;
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
this.Configuration.LazyLoadingEnabled = false;
<#
}
I have added the property base.Configuration.ProxyCreationEnabled = false;
so that it will be the very first line in the constructor.
Save your file, and open the Model1.Context.cs file to see the resulting code. If you want to force the template script to run, select the menu
Build - Tranform all T4 templates
It is easy to know if you've made a mistake in your T4 code, as the .cs file will be either not made at all, or with obvious errors if you open it in the editor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With