【问题标题】:Fluent NHibernate - ProjectionList - ICriteria is returning null valuesFluent NHibernate - ProjectionList - ICriteria 返回空值
【发布时间】:2014-09-26 18:29:44
【问题描述】:

我是 NHibernate 的新手,但我用谷歌搜索并没有找到任何可以帮助解决这个问题的东西。我希望你们能! ;) 我正在更改属性和方法的名称,因为这段代码是公司的财产,但基本上这就是我需要帮助的地方。

我有以下场景:

我的域实体:

public class Structure
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Person Manager { get; set; } //I need to fill here.
    //and others
}

我的地图类:

public class MapStructure : ClassMap<Structure>
{
    public MapStructure()
    {
        Table("TB_Structure");
        Id(x => x.Id).Column("Id").GeneratedBy.Identity();
        Map(x => x.Name).Column("Name");
        References<Person>(x => x.Manager).Column("PersonId").Fetch.Join().NotFound.Ignore();
        //...
    }
}

存储库:

    public IEnumerable<T> SelectByColumns()
    {
        ICriteria searchCriteria = _sessao.CreateCriteria<T>("this");

        searchCriteria.CreateAlias("this.Manager", "Manager");

        //Only for example purpose. Those columns come as an array string parameter, but the treatment is the same one.
        var columns = Projections.ProjectionList();
        columns.Add(Projections.Property("Manager.Id"));
        columns.Add(Projections.Property("Manager.Name"));
        columns.Add(Projections.Property("Manager.Document"));

        searchCriteria.SetProjection(columns);
        searchCriteria.SetResultTransformer(Transformers.AliasToBean<T>());

        return searchCriteria.List<T>();
    }

最后是电话:

public IEnumerable<Person> GetManager()
{
    using (IDbSession dbSession = _sessionFactory.Create())
    {
        try
        {
            IRepository<Structure> _repository = dbSession.CreateRepository<Structure>();
            IEnumerable<Structure> structureList = _repository.SelectByColumns();

            var managerList = (from structure in structureList
                                where structure.Manager != null
                                select new Person()
                                {
                                    Id = structure.Manager.Id,
                                    Name = structure.Manager.Name,
                                    Document = structure.Manager.Document
                                });

            return managerList.OrderBy(x => x.Name);
        }
        catch (Exception)
        {
            throw;
        }
    }
}

这会生成一个如下所示的 sql 查询:

SELECT manager1_.PersonId as y0_, manager1_.Name as y1_, manager1_.Document as y2_
FROM TB_Structure this_
inner join TB_Person manager1_ on this_.ManagerId=manager1_.PersonId

而这正是我所需要的。如果我在 Management Studio 中运行此查询,我会得到我所期望的所有结果。

但是当我到达 var managerList 时,结构列表中的所有记录都是从 sql 返回的,但都是空值,如图所示:

我已经尝试过使用 CreateAlias、CreateCriteria、return IList、return IEnumerable。 我已经将 Transformers.AliasToBean() 更改为 Transformers.AliasToEntityMap。 我在谷歌上发现了很多不同的东西,但我总是得到相同的结果。

感谢您的帮助,感谢您的宝贵时间!

【问题讨论】:

    标签: c# nhibernate fluent-nhibernate nhibernate-criteria nhibernate-projections


    【解决方案1】:

    你快到了。我们需要的是正确地将 Projections 转换为实体/对象树。这需要两个步骤:

    我。为每一列使用别名

    列别名对于事后处理比 SQL 语句生成更有用。但这是下一步的必须。所以不要这样:

    columns.Add(Projections.Property("Manager.Id"));
    columns.Add(Projections.Property("Manager.Name"));
    columns.Add(Projections.Property("Manager.Document"));
    

    我们需要这个:

    columns.Add(Projections.Property("Manager.Id").As("Manager.Id");
    columns.Add(Projections.Property("Manager.Name").As("Manager.Name"));
    columns.Add(Projections.Property("Manager.Document").As("Manager.Document"));
    

    事实上,如果我们使用第一级 (no JOIN) 实体,这就足够了。对于 JOINed 参考树 (多对一) 它将不起作用。但是

    二。使用自定义结果转换器

    与往常一样,NHibernate 为自定义扩展提供了许多开放点。其中之一是自定义 IResultTransformer。我们需要的,准备好处理的参考树在这里:

    在我们的解决方案中,我们应该代替这个:

    searchCriteria.SetResultTransformer(Transformers.AliasToBean<T>());
    

    使用这个:

    searchCriteria.SetResultTransformer(new DeepTransformer<T>());
    

    此实现强烈依赖于正确的别名设置,描述真实的实体属性(使用反射来查找要设置的内容)。所以第一点——列/属性别名真的很重要

    【讨论】:

    • 非常感谢@Radim Köhler!真的节省了一周!
    • 很高兴看到这一点,先生! ;) 享受惊人的 NHibernate ;)
    • 我正在使用你正在使用的这个 DeepTransformer,它非常方便。但是,在这个问题中,如果“经理”可以为空且不存在,您需要做什么?根据我的复制经验,如果 manager 为空,则投影会跳过所有这些行,它们甚至不会进入结果转换器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-05
    • 1970-01-01
    • 2011-12-25
    • 2010-10-09
    相关资源
    最近更新 更多