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