【问题标题】:How do virtual proxies work?虚拟代理如何工作?
【发布时间】:2011-06-15 19:43:11
【问题描述】:

我在处理虚拟代理时遇到了一些麻烦。我已经阅读了大量文章并花了几个小时试图找到好的信息,但我还没有找到全面的东西。因此,我将在此处提出一般性请求以获取更好的信息(在此处发布或仅提供链接)。我还将在下面添加一些细节,以更好地解释我到底想要什么。

我有几个对象,它们之间有很多引用。为简洁起见,我将有一个具有基本父子关系的对象(节点)。当我从数据库中拉出这个对象时,我想实现延迟加载。根据我的阅读,虚拟代理将通过引用接口(INode)并根据需要拉取数据成员来为我处理所有延迟加载。 [注意:我实际上没有 INode 类,但是当我将 virtual 关键字放在我的数据成员上时,似乎确实使用了代理]

当我将我的类中的数据成员设为虚拟时,它似乎是一个代理。这是虚拟代理吗?这些是否实现了延迟加载?

我搜索了有关 virtual 关键字的信息,但我能找到的唯一文档是在方法上使用它,它用于继承,以便派生类可以覆盖该函数,这与我想要的无关(我认为)。

这是我当前的 Node.cs

[DataContract(IsReference=true)]
public partial class Node
{
  [DataMember]
  public long ID { get; private set; }
  [DataMember]
  public virtual Node Parent { get; set; }
  [DataMember]
  public virtual ICollection<Node> Children { get; set; }
}

基本上在这一点上我很困惑,只需要一些关于这个主题的指导,甚至是我可以查看的在线资源,因为我发现的所有资源都没有帮助。

提前致谢。

【问题讨论】:

    标签: c# wcf proxy virtual


    【解决方案1】:

    “虚拟”代理和延迟加载与 ORM 工具有关。代理实际上不是虚拟的,它是动态的,它遵循 GoF 定义的真实代理模式。

    动态代理是由 ORM 工具在运行时创建的类(它没有在任何地方定义为代码文件)。它派生自您的实体并覆盖导航属性。因此,它们必须是虚拟的才能使代理工作。代理在私有字段或更复杂的结构中保存导航属性的状态,如果第一次访问该属性,它会看到状态已卸载并触发从数据库加载并将状态更改为已加载。

    无论如何,我不确定这如何指代 WCF,因为最佳做法是不使用 WCF 的延迟加载。为什么?

    • 如果您在服务器端使用延迟加载,序列化将始终从数据库中提取整个对象图,因为序列化将访问每个导航属性并触发延迟加载,但随后它将开始序列化延迟加载的实体并访问其所有导航属性等。
    • 客户端的延迟加载有些模糊。首先,客户端的延迟加载完全取决于您 - 您必须实现它。使用服务时,您应该始终遵循 SOA 原则之一:服务边界是明确的。这意味着您的对象的用户应该始终知道他正在进行远程调用而不是本地调用。分布式计算的主要目标是减少网络往返,因此您应该使用预先加载并尽可能在一次往返中传输所有需要的数据,而不是使用延迟加载。这同样适用于从数据库加载 - 在有意义的情况下使用延迟加载,因为往返数据库可能是昂贵的操作。

    【讨论】:

    • 1.如果我无论如何都要使用动态代理,我该如何序列化/反序列化?我看过一篇关于 DataContractResolver 的文章的链接,但我从来没有让它工作。 2. 我尝试通过 DbContext.Configuration 关闭延迟加载,但我的对象引用仍然为空。 WCF RIA 是否只是不让我不延迟加载?
    • 如果您使用 WCF RIA 服务,您应该在问题和标签中提及它,因为它是非常具体的技术。
    • 抱歉并不是要输入 RIA :P。我在标签之间跳来跳去,忘记了我正在输入的内容。只是想说WCF。我可以让它不延迟加载的唯一方法是 A. 使用显式 .Include ,这很烦人,因为我的模型中有许多关系,或者 B. 使用动态代理,然后失败,因为我无法序列化动态代理以供使用在我的服务中。我对这一切都很陌生,基本上已经碰壁了。
    • 正确的方法是使用.Include() 并明确定义要传递给客户端的内容,否则延迟加载+序列化可以轻松拉取整个数据库。另一种方法是不发送真实实体并定义特殊的数据传输对象仅用于传输数据 - 您必须加载实体并将其转换为数据传输对象。但无论如何,这又回到了开头——你知道你想要传输什么,所以这不是延迟加载的场景。
    【解决方案2】:

    我认为您需要一些私有字段来支持您的虚拟属性。在这些虚拟属性的获取覆盖中,您检查私有字段以查看其当前是否有效(是否已经从数据库中获取,是否是最新的等) - 如果没有,则获取或重新获取它。我不认为它必须比这更复杂。

    基类:

    private Node _Parent;
    public virtual Node Parent { 
        get { return _Parent; } // Default no lazy fetch.
    }
    

    覆盖:

    public override Node Parent {
        get {
            if (_Parent==null) // or out of date, dirty etc
                Do_db_get_of_parent();
            return _Parent;
        }
    }
    

    【讨论】:

    • 我想我不明白这如何解决我的问题。你能不能写一个快速的代码sn-p?
    猜你喜欢
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多