Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the downsides to turning off ProxyCreationEnabled for CTP5 of EF code first

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.

like image 522
Ralph Shillington Avatar asked Jan 04 '11 17:01

Ralph Shillington


4 Answers

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.

like image 69
ALT Avatar answered Sep 30 '22 00:09

ALT


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.

like image 40
Ladislav Mrnka Avatar answered Sep 30 '22 02:09

Ladislav Mrnka


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

like image 29
Vicente Zambrano Avatar answered Sep 30 '22 02:09

Vicente Zambrano


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

like image 25
Per Malmstedt Avatar answered Sep 30 '22 01:09

Per Malmstedt