将NHibernate POCO复制到DTO,而不会触发延迟加载或渴望加载



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

SO上的几个类似问题得到的答案要么是:

  1. 建议会话.GetSessionImplementation().PersistenceContext.Unpoxy()
  2. 建议关闭"懒惰加载"

在我的情况下,第一个建议无关紧要,因为根据我的理解,它会导致急于加载以替换代理。事实上,它甚至不起作用——它不会删除我的对象中的代理。(有什么解释吗?)

第二个建议,关闭延迟加载似乎会导致所有引用和集合都急于加载,基本上是加载整个DB。我的预期是,如果延迟加载关闭,并且我没有请求集合,它将不会被加载。(NHibernate没有提供这样的选择,我是对的吗?)

我使用的是配置流畅的NHibernate 3.3.1。

为了重申我的主要问题,我需要创建没有代理的DTO,从包含代理的POCO复制,并且我不想加载这些代理后面的数据。

任何有用的建议,包括示例代码并使用ValueInjecter/AutoMapper自动化流程,都将非常有用。

编辑#1:

根据Roger Alsing关于使用投影的建议,我意识到我真正想要的是一个类似ValueInjecter的基于约定的映射。原因如下。最初,我的DTO将被定义为与模型的POCO相同。这是由于庞大的代码库依赖于客户端项目上传输的现有POCO。

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

使用ValueInjecter,我将能够在一次调用中按照约定填充DTO,而无需编写特定的预测,也无需在将来维护这些预测。也就是说,如果我能够让ValueInjecter忽略Proxy对象。

考虑到在我的情况下,使用投影是一个很好但不理想的解决方案,有没有一种方法可以配置ValueInjecter之类的东西来复制POCO,而不复制代理或在复制时触发急切/懒惰加载

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

例如

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

这样,你就不需要求助于反射魔法或任何其他花哨的东西。查询一次获取所需的内容,因此,这通常比获取实体然后在mem中将它们转换为DTO要高效得多。(在某些情况下,无论出于何种原因,如果生成的SQL查询包含额外的联接,则效率可能会降低。)

我正在使用以下带有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);
    }
}

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

并且在指定一个不会触及代理属性的约定之后

这是一个开始:

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

看看NH 3.0 中QueryOver简介中的投影

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>();

最新更新