85

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.

Ryan Gates
  • 4,501
  • 6
  • 50
  • 90
Ralph Shillington
  • 20,718
  • 23
  • 91
  • 154
  • "WCF service can return classes from a code first model" - you really shouldn't be using domain/entity types as DTOs _anyway_. DTOs are not business objects. – Dai Jun 08 '21 at 06:53

4 Answers4

79

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.

ALT
  • 1,202
  • 11
  • 7
72

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.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 8
    Is there a performance benefit to disabling ProxyCreationEnabled? I frequently grab a DbContext instance just to do a read with eager loading, for example. – Chris Moschini May 18 '13 at 16:21
  • 3
    @ChrisMoschini "When a POCO entity does not have a change tracking proxy, changes are found by comparing the contents of your entities against a copy of a previous saved state. This deep comparison will become a lengthy process when you have many entities in your context, or when your entities have a very large amount of properties, even if none of them changed since the last comparison took place." https://msdn.microsoft.com/en-us/library/hh949853(v=vs.113).aspx – Niklas Peter Feb 17 '18 at 08:43
  • @NiklasPeter Conversely, from the same link you provided: "Note that creating a proxy entity will typically be more expensive than creating a non-proxy POCO entity due to the added set of events created by Entity Framework." - of course, never speculate: profile first. – Dai May 24 '22 at 05:12
10

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

My Stack Overfloweth
  • 4,729
  • 4
  • 25
  • 42
  • 2
    This is not an answer but it helped me anyway. – Akira Yamamoto Sep 23 '14 at 22:14
  • 1
    Do you have a good suggestion on how to automate the process of putting in that line? Every time I'll recreate a model, I'm surely bound to forget to set the property to *false* and that can take hours of debugging before someone realizes what's wrong with it. – Konrad Viltersten Dec 27 '15 at 16:58
  • @konrad - Create the code in a partial class so it does not get overridden. *public partial class yourDataMoldelEntities()* – Mikee Feb 04 '16 at 19:42
  • @Mikee Really? I would expect some kind of problems due to the auto-generated constructor colliding with the one written by me in the partial class... – Konrad Viltersten Feb 04 '16 at 19:45
  • @konrad they created the partial class 'type' to give you a wayto not have your code overwritten – Mikee Feb 04 '16 at 19:50
  • @Mikee I fear that I wasn't clear with my worry. If I have a partial class *Blobb* with a constructor *public Blobb(){...}* and there's another file containing the rest of the the partial class *Blobb*, also containing a constructor *public Blobb(){...}*, the code won't compile. If one of the partials is auto-generated, then the programmer will have to manually correct that file each time the auto-generation take place. Correct? Or is there a smooth way to handle that, which I'm ignorant of? Please educate me. I'm a fan of smooth ways, hehe. – Konrad Viltersten Feb 05 '16 at 08:37
  • @KonradViltersten Just overload the contructor by changing your own constructor's signature. You can do this by adding a dummy parameter, e.g. `public Blobb(bool dummy = true){...}`. Personally, I use `public Blobb(string connectionString) : base(connectionString)` because I don't like storing credentials in my AppSettings file. – Dan Bechard Apr 27 '17 at 19:53
6

(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.

Per Malmstedt
  • 351
  • 1
  • 3
  • 9
  • Wow - this really should be the preferred solution since it fixes the problem at the root. And also provides a good background on the relationship of the *.tt file with the resulting *.cs file. – Douglas Timms Jun 29 '19 at 03:57