将NHibernate POCO复制到DTO而不会触发延迟加载或急切加载

时间:2012-08-05 13:13:41

标签: nhibernate automapper poco dto valueinjecter

我需要从 NHibernate POCO 对象创建 DTO 。问题是POCO对象包含动态代理,不应将其复制到DTO。 我急需加载我需要提前传输的所有集合和引用,我不希望NHibernate开始加载我没有提前加载的引用集合。

关于SO的几个类似问题得到了答案:

  1. 建议Session.GetSessionImplementation()。PersistenceContext.Unproxy();
  2. 建议关闭延迟加载。
  3. 在我的情况下,第一个建议是无关紧要的,因为根据我的理解,它会导致急切的加载来替换代理。实际上,它甚至不起作用 - 它不会删除我的对象中的代理。 (任何解释为什么?)

    第二个建议,关闭延迟加载似乎导致所有引用和集合急切加载,基本上加载整个数据库。我的期望是,如果延迟加载,我没有请求集合,它将不会被加载。 (我是否认为NHibernate没有这样的选择?)

    我正在使用NHibernate 3.3.1和流畅的配置。

    重申我的主要问题,我需要创建DTO清理代理,从包含代理的POCO复制,我不想加载这些代理背后的数据。

    任何有用的建议,包括示例代码,并使用ValueInjecter / AutoMapper自动执行该过程将非常有帮助。

    编辑#1:

    遵循Roger Alsing建议使用投影,我意识到我实际上正在寻找的是类似于ValueInjecter的基于约定的映射。这就是原因。最初,我的DTO定义与模型的POCO相同。这是由于代码库很大,这取决于在客户端项目上传输的现有POCO。

    使用投影,我将必须指定必须复制哪个字段子集,并且该子集在每个上下文中可能不同(理想情况下,DTO会有所不同)。这意味着当应该有第二个选项时,会向服务器端引入许多新代码。

    使用ValueInjecter,我将能够在一次调用中按惯例填充DTO,而无需编写特定的预测,或者必须将这些预测保留在未来。也就是说,如果我能够让ValueInjecter忽略代理对象。

    鉴于在我的情况下使用投影是一个很好但不理想的解决方案,有没有办法配置像ValueInjecter这样的东西来复制POCO而无需复制代理或在副本上触发急切/延迟加载? < / p>

4 个答案:

答案 0 :(得分:5)

我通过使用Linq或O / R Mapper可能具有的任何查询语言选择DTO作为投影来解决此问题。

e.g。

return from c in customers 
       select new CustomerDTO 
       {
          Name = c.Name , 
          Orders = c.Orders.Select (o => new OrderDTO {...} ) 
       };

这样,你不需要诉诸反射魔法或任何其他花哨的东西。 并且查询一次性获取您需要的内容,因此,这通常比获取实体然后将它们转换为mem中的DTO更有效。 (在某些情况下,由于任何原因导致SQL查询包含额外的连接,效率可能会降低。)

答案 1 :(得分:2)

我在AutoMapper中使用以下ValueResolver:

/// <summary>
/// ValueResolver that will set NHibernate proxy objects to null, instead of triggering a lazy load of the object
/// </summary>
public class IgnoreNHibernateProxyValueResolver : IValueResolver
{
    public ResolutionResult Resolve(ResolutionResult source)
    {
        var prop = source.Type.GetProperty(source.Context.MemberName).GetValue(source.Value, null);
        var proxy = prop as INHibernateProxy;
        if (proxy != null && proxy.HibernateLazyInitializer.IsUninitialized)
        {
            return source.Ignore();
        }

        return source.New(prop);
    }
}

答案 2 :(得分:1)

Introduction to QueryOver in NH 3.0

中查看预测
CatSummary summaryDto = null;
IList<CatSummary> catReport =
    session.QueryOver<Cat>()
        .SelectList(list => list
            .SelectGroup(c => c.Name).WithAlias(() => summaryDto.Name)
            .SelectAvg(c => c.Age).WithAlias(() => summaryDto.AverageAge))
        .TransformUsing(Transformers.AliasToBean<CatSummary>())
        .List<CatSummary>();

答案 3 :(得分:1)

对于ValueInjecter解决方案我建议使用SmartConventionInjection(您需要将链接页面中的代码复制到您的解决方案中)

并指定一个不会触及代理属性的约定

这是一个开始:

public class MapPoco: SmartConventionInjection
{
     protected override bool Match(SmartConventionInfo c)
     {
         return c.SourceProp.Name == c.TargetProp.Name;
     }
}