3

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

关于 SO 的几个类似问题收到的答案是:

  1. 建议 Session.GetSessionImplementation().PersistenceContext.Unproxy();
  2. 建议关闭延迟加载。

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

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

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

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

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

编辑#1:

遵循 Roger Alsing 的使用投影的建议,我意识到我真正在寻找的是一个类似于 ValueInjecter 的基于约定的映射。这就是为什么。最初,我的 DTO 将与模型的 POCO 定义相同。这是由于庞大的代码库依赖于在客户端项目上传输的现有 POCO。

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

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

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

4

4 回答 4

5

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

例如

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

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

于 2012-08-05T15:07:44.333 回答
2

我将以下 ValueResolver 与 AutoMapper 一起使用:

/// <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);
    }
}
于 2013-08-28T16:45:39.863 回答
1

查看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>();
于 2012-08-05T13:45:02.247 回答
1

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

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

这是一个开始:

public class MapPoco: SmartConventionInjection
{
     protected override bool Match(SmartConventionInfo c)
     {
         return c.SourceProp.Name == c.TargetProp.Name;
     }
}
于 2012-08-05T15:19:21.363 回答