Каковы недостатки предварительного отключения ProxyCreationEnabled для CTP5 кода EF

82

Единственный способ, которым моя служба WCF может возвращать классы из модели с первым кодом, - это установить ProxyCreationEnableдля falseиспользования следующий код.

((IObjectContextAdapter)MyDb).ObjectContext.ContextOptions.ProxyCreationEnable = false;

Каковы негативные последствия этого? Одним из преимуществ является то, что я могу по крайней мере сериализовать эти динамические типы, чтобы их можно было отправлять по сети с помощью WCF.

Ральф Шиллингтон
источник

Ответы:

71

Динамические прокси используются для отслеживания изменений и отложенной загрузки. Когда WCF пытается сериализовать объект, связанный контекст обычно закрывается и удаляется, но сериализация свойств навигации автоматически запускает отложенную загрузку (в закрытом контексте) => исключение.

Если вы отключите отложенную загрузку, вам нужно будет использовать активную загрузку для всех свойств навигации, которые вы хотите использовать (Включить в ObjectQuery). Отслеживание изменений не работает в WCF, оно работает только для модификации сущности, прикрепленной к ObjectContext.

Ладислав Мрнка
источник
7
Есть ли преимущество в производительности при отключении ProxyCreationEnabled? Я часто беру экземпляр DbContext, например, просто для чтения с активной загрузкой.
Крис Москини
2
@ChrisMoschini "Когда объект POCO не имеет прокси для отслеживания изменений, изменения обнаруживаются путем сравнения содержимого ваших объектов с копией предыдущего сохраненного состояния. Это глубокое сравнение станет длительным процессом, если в вашем контексте много объектов. , или когда ваши объекты имеют очень большое количество свойств, даже если ни одно из них не изменилось с момента последнего сравнения ". msdn.microsoft.com/en-us/library/hh949853(v=vs.113).aspx
Никлас Питер
75

Если DbContext.Configuration.ProxyCreationEnabledустановлено значение false, DbContext не будет загружать дочерние объекты для некоторых родительских объектов, если Includeметод не вызывается для родительского объекта. Установка DbContext.Configuration.LazyLoadingEnabledна trueили falseне будет иметь никакого влияния на его поведение.

Если DbContext.Configuration.ProxyCreationEnabled установлено значение true, дочерние объекты будут загружаться автоматически, а DbContext.Configuration.LazyLoadingEnabledзначение будет управлять загрузкой дочерних объектов.

Алексей Тимков
источник
10

Когда вы используете EF, он по умолчанию создает прокси для вашего класса. Решением может быть добавление этой строки в конструктор вашего класса DbContext. Ваша модель данных унаследована от класса DbContext, поэтому вы можете редактировать свою модель следующим образом:

    public yourDataModelEntities()
        : base("name=yourDataModelEntities")
    {
        base.Configuration.ProxyCreationEnabled = false;
    }

Этот класс в вашем EF.edmxзатем в yourmodel.Context.ttтоyourmodel.Context.cs

Висенте Самбрано
источник
2
Это не ответ, но мне все равно помогло.
Акира Ямамото
1
У вас есть хорошее предложение, как автоматизировать процесс установки этой строки? Каждый раз, когда я воссоздаю модель, я обязательно забываю установить для свойства значение false, и это может занять несколько часов на отладку, прежде чем кто-то поймет, что с ней не так.
Конрад Вильтерстен
@konrad - Создайте код в частичном классе, чтобы его не переопределить. публичный частичный класс yourDataMoldelEntities ()
Майк,
@Mikee Серьезно? Я бы ожидал каких-то проблем из-за того, что автоматически сгенерированный конструктор сталкивается с тем, который был написан мной в частичном классе ...
Конрад Вилтерстен
@konrad они создали «тип» частичного класса, чтобы дать вам возможность не перезаписывать ваш код
Майк,
6

(Используя Visual Studio 2013 или новее)

Чтобы избежать редактирования конструктора класса в вашей модели EF каждый раз, когда вы обновляете модель из базы данных или каким-либо другим способом запускаете перестройку кода, правильное место для внесения изменений находится в файле кода T4, который отвечает за собственно создание кода модели. Несколько лет назад у меня была другая проблема с динамическими свойствами, когда я понял основную механику того, как на самом деле создаются классы и свойства. Т4 !!! Какое это чудо: -D Синтаксис T4 поначалу может показаться немного пугающим, так что читать о синтаксисе будет разумно. ОЧЕНЬ сосредоточиться при внесении изменений - тоже хорошая идея :-)

Так! Если вы посмотрите в свою модель, у вас есть файл .tt под вашим файлом .edmx. Этот файл .tt (T4) представляет собой сценарий, который фактически создает класс вашей модели. Скрипт будет запускаться автоматически каждый раз, когда вы создаете модель или вносите какие-либо изменения в редактор модели.

Допустим, ваш дескриптор модели называется Model1.edmx . У вас будет файл с именем Model1.Context.tt в дереве под ним. Вы также увидите файл Model1.Context.cs . Очевидно, это фактический файл кода для вашего контекста. Но этот файл - результат запуска файла сценария .tt ! Он полностью динамически создан. Так что не знаю, редактировать это.

Откройте файл .tt, и вы увидите что-то вроде:

<#@ 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);
..
..

Еще примерно на 50 строк ниже код конструктора пишется.

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;
    <#
    }

Я добавил свойство, base.Configuration.ProxyCreationEnabled = false;так что оно будет самой первой строкой в ​​конструкторе.

Сохраните файл и откройте файл Model1.Context.cs, чтобы увидеть полученный код. Если вы хотите принудительно запустить сценарий шаблона, выберите меню

Сборка - преобразование всех шаблонов T4

Легко узнать, допустили ли вы ошибку в коде T4, так как файл .cs будет либо не создан, либо с очевидными ошибками, если вы откроете его в редакторе.

Пер Мальмштедт
источник
Вау - это действительно должно быть предпочтительным решением, поскольку оно устраняет проблему в корне. А также дает хорошее представление о взаимосвязи файла * .tt с результирующим файлом * .cs.
Дуглас Тиммс