【问题标题】:How can we reduce the property proxying overhead of NHibernate?我们如何减少 NHibernate 的属性代理开销?
【发布时间】:2012-05-12 05:47:04
【问题描述】:

我们正在使用 Fluent NHibernate 1.3.0.727 和 NHibernate 3.3.0.4000 将我们的属性映射到数据库中的列。这是我们的一个 ClassMap 的缩略示例:

    public class TankMap : ClassMap<Tank>
    {
        public TankMap()
        {
            Id(o => o.Id);
            Map(o => o.TankSystem);
        }
    }

在这种情况下,TankSystem 属性是一个字符串。

在我们的应用程序的某些部分中,有很多计算涉及多次访问映射的属性(例如 TankSystem)。当我们分析应用程序时,简单地访问这些属性会占用大量时间,因为每次访问它们时,都必须通过 NHibernate.Proxy.DefaultLazyInitializer.Intercept 方法。

我们需要尽可能快地进行计算,并希望避免这种代理开销。一种方法是将我们想要的属性(例如 TankSystem)复制到数组中,并在我们想要访问此信息的任何时候使用数组,但这不是一种非常面向对象的方法。

更新:

我们已经尝试使用 Not.LazyLoad 映射我们的属性,例如:

Map(o => o.TankSystem).Not.LazyLoad();

但是,这似乎对该属性是否实际被代理没有任何影响。

有没有什么办法可以避免/减少这种代理开销?

【问题讨论】:

  • NHibernate 3.x 不使用 Castle DynamicProxy。因此,我认为这个问题是错误的

标签: performance nhibernate fluent-nhibernate proxy castle-dynamicproxy


【解决方案1】:

是的! .Not.LazyLoad()救援!

    public TankMap()
    {
        Id(o => o.Id);
        Map(o => o.TankSystem).Not.LazyLoad();
    }

我找到了一个很好的简短解释:

您可能想知道 Not.LazyLoad() 是什么意思。默认情况下,Fluent NHibernate 定义映射以使用延迟加载。但这也意味着我们实体的所有属性都必须是虚拟的(代理)。

source

【讨论】:

  • 我曾尝试过这种方法,但似乎没有什么不同 - TankSystem 属性仍在被代理。我们使用的是旧版本的 FluentNHibernate (1.2.0.712),因此此更改可能在更高版本中有效 - 我将尝试升级到最新版本,看看是否有帮助!
  • 不幸的是,这种方法似乎对我们没有任何作用。使用 dotTrace 进行分析仍然表明,任何 No.LazyLoad 属性的调用仍然通过 NHibernate.Proxy.DefaultLazyInitializer.Intercept 方法。
  • @GeoffHardy。但这并不是说你得到了代理!当你更新时,写 Update 因为你的更新让所有的答案看起来都很愚蠢。
【解决方案2】:

我会非常小心在您的映射中使用 .Not.LazyLoad() 并根据需要在查询中急切加载。如果延迟加载获取策略配置不正确,问题可能会出现。最好使用 NHProf 之类的工具检查每个查询。

林克:

var tanks = _session.Linq<Tank>()
               .Fetch(x=>x.TankSystem)
               .ToList();

QueryOver(我的偏好): var tank = _session.QueryOver() .Fetch(x=>x.TankSystem).Eager .List();

TankSystem tankSystemAlias = null;
var tanks = _session.QueryOver<Tank>()
                .JoinAlias(x=>x.TankSystem, () => tankSystemAlias, JoinType.InnerJoin) // or JoinType.LeftOuterJoin
                .List()

【讨论】:

    【解决方案3】:

    避免对象具有虚拟属性的一种方法是:

    public TankMap()
    {
            Id(o => o.Id);
            this.Not.LazyLoad(); 
            Map(o => o.TankSystem);
    }
    

    这种方式没有属性代理魔法。

    【讨论】:

    • 如果我没记错的话,它将使 所有 属性不会被延迟加载,这可能会对性能造成巨大影响!
    • 是的,它会,所以没有一个属性需要是虚拟的。如果确实需要延迟加载某些属性,这只会影响性能。
    • 如果你多次这样做,你可以在单行查询后将整个数据库放在内存中。所以我更喜欢将.Not.LazyLoad() 设置在property 级别而不是class 级别。
    • 只有当你有一个非常深的对象图并且所有实体都可以通过所有其他实体的关联来访问时,整个数据库才会被加载到内存中,无论如何这是一个糟糕的设计。我一直在努力避免一起延迟加载,而是专注于保持实体小。
    猜你喜欢
    • 2014-04-10
    • 2014-03-05
    • 2023-03-11
    • 1970-01-01
    • 2010-11-21
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多