首先关闭 EF 代码的 CTP5 的 ProxyCreationEnabled 有啥缺点

Posted

技术标签:

【中文标题】首先关闭 EF 代码的 CTP5 的 ProxyCreationEnabled 有啥缺点【英文标题】:What are the downsides to turning off ProxyCreationEnabled for CTP5 of EF code first首先关闭 EF 代码的 CTP5 的 ProxyCreationEnabled 有什么缺点 【发布时间】:2011-06-03 12:58:20 【问题描述】:

我的 WCF 服务可以从代码优先模型返回类的唯一方法是使用下面的代码将 ProxyCreationEnable 设置为 false

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

这样做的负面后果是什么?一个好处是我至少可以将这些动态类型序列化,以便可以使用 WCF 通过网络发送它们。

【问题讨论】:

“WCF 服务可以从代码优先模型返回类” - 你真的不应该使用域/实体类型作为 DTO无论如何。 DTO 不是业务对象。 【参考方案1】:

如果DbContext.Configuration.ProxyCreationEnabled 设置为false,DbContext 将不会为某些父对象加载子对象,除非在父对象上调用Include 方法。将DbContext.Configuration.LazyLoadingEnabled 设置为truefalse 不会对其行为产生影响。

如果DbContext.Configuration.ProxyCreationEnabled设置为true,子对象将自动加载,DbContext.Configuration.LazyLoadingEnabled值将控制何时加载子对象。

【讨论】:

【参考方案2】:

动态代理用于更改跟踪和延迟加载。当 WCF 尝试序列化对象时,相关上下文通常会关闭并释放,但导航属性的序列化会自动触发延迟加载(在关闭的上下文中)=> 异常。

如果您关闭延迟加载,您将需要对所有要使用的导航属性使用预先加载(ObjectQuery 上的包含)。跟踪更改不适用于 WCF,它仅适用于修改附加到 ObjectContext 的实体。

【讨论】:

禁用 ProxyCreationEnabled 是否有性能优势?例如,我经常抓取一个 DbContext 实例只是为了通过预先加载进行读取。 @ChrisMoschini "当 POCO 实体没有更改跟踪代理时,通过将实体的内容与之前保存的状态副本进行比较来发现更改。这种深度比较将成为一个漫长的过程当您的上下文中有许多实体时,或者当您的实体具有大量属性时,即使自上次比较以来它们都没有改变。” msdn.microsoft.com/en-us/library/hh949853(v=vs.113).aspx【参考方案3】:

当您使用 EF 时,它会默认为您的班级创建一个代理。一个解决方案是在 DbContext 类的构造函数中添加这一行。您的数据模型继承自 DbContext 类,因此您可以像这样编辑模型:

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

这个类在你的EF.edmx 然后在yourmodel.Context.tt 然后在yourmodel.Context.cs

【讨论】:

这不是一个答案,但它对我有帮助。 您对如何自动化放入该生产线的过程有什么好的建议吗?每次我要重新创建一个模型时,我肯定会忘记将属性设置为 false,这可能需要数小时的调试才能有人意识到它有什么问题。 @konrad - 在部分类中创建代码,这样它就不会被覆盖。 公共部分类 yourDataMoldelEntities() @Mikee 真的吗?由于自动生成的构造函数与我在部分类中编写的构造函数发生冲突,我预计会出现某种问题...... @konrad 他们创建了部分类 'type' 来给你一种不让你的代码被覆盖的方法【参考方案4】:

(使用 Visual Studio 2013 或更高版本)

为了避免每次从数据库中刷新模型时编辑 EF 模型中的类构造函数,或以其他方式触发代码的重建,进行更改的正确位置是在 T4 代码文件中负责实际创建模型代码。 几年前,当我了解如何实际创建类和属性的基本机制时,我遇到了其他一些关于动态属性的问题。 T4!!!真是个奇迹:-D T4 语法起初可能有点吓人,因此阅读语法是明智的。在进行更改时非常专注也是一个好主意:-)

所以!如果您查看模型,您的 .edmx 文件下有一个 .tt 文件。这个 .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 文件之间关系的良好背景。

以上是关于首先关闭 EF 代码的 CTP5 的 ProxyCreationEnabled 有啥缺点的主要内容,如果未能解决你的问题,请参考以下文章

EF4 CTP5 Code First 方法忽略表属性

EF4 CTP5 代码优先实现中的实体拆分场景

使用实体基类时的 EF CTP5 映射问题

EF CTP5 中的modelBuilder.IncludeMetadataInDatabase 在哪里?

EF4 Code only ctp5:如何设置连接字符串 devart oracle?

WCF 数据服务和 EF4 CTP5,如何为查询配置默认的急切加载模式?