2

我在NHibernate中很新,但我已经搜索了一下,并没有发现任何可以帮助解决这个问题的东西。我希望你们能! ;) 我正在改变属性和方法的名称,因为这个代码是公司的财产,但基本上这是我需要一些帮助。Fluent NHibernate - ProjectionList - ICriteria返回空值

我有以下情形:

我的域实体:

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 

而这正是我需要的。如果我在管理工作室中运行这个查询,我得到了我期待的所有结果。

Result

但是,当我到达了var managerList,该structureList有所有的记录从SQL返回,但如所有空值:

After run sql query

我已经与CreateAlias tryed, CreateCriteria,返回IList <>,返回IEnumerable。 我已经将Transformers.AliasToBean()更改为Transformers.AliasToEntityMap。 很多不同的东西,我发现谷歌搜索,但我总是得到相同的结果。

我感谢任何帮助,并感谢您的时间!

回答

2

你几乎在那里。我们需要的是将投影正确转换为实体/对象树。这需要两个步骤:

一,使用别名为每列

列别名,是非常有用的多为事后处理,比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")); 

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

二,使用定制的结果变换器

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

有,在我们的解决方案,我们应该不是这样的:

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

使用本:

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

该实现强烈依赖于正确的别名设置descr ibing真正的实体属性(使用反射来查找要设置的内容)。所以第一点 - 列/属性别名是非常重要的

+0

非常感谢@RadimKöhler!真的节省了一周! – 2014-09-27 16:32:59

+0

很高兴看到,先生! ;)享受惊人的NHibernate;) – 2014-09-27 16:33:23

+0

我正在使用你正在使用的DeepTransformer,它的方便性令人难以置信。 Howevever,在这个问题中,如果'管理者'可以为空并且不存在,你需要做什么?根据我的经验复制这个,如果经理是空的,投影会跳过所有这些行,他们甚至不把它交给结果转换器。 – user99999991 2016-03-05 00:32:03