2014-10-04 46 views
0

例如查詢層次結構的數據,如果我有這樣的功能NHibernate - 從底部

id | parent_id 
----------------- 
1 | null 
2 | 1 
3 | 1 
4 | 1 
5 | 2 
6 | 3 
7 | 3 
8 | 4 
9 | 7 
.... 

表層次樹看起來就像這樣:

      X1 
          | 
------------------------------------------------------ 
|       |       | 
X2      X3       X4 
|       |       | 
|    ------------------     | 
|    |    |     | 
X5    X6    X7     X8 
            | 
            X9 

那麼,有沒有反正,我可以使用QueryOverCriteria查詢,當我輸入id時,它會將所有parent_id(或父對象)的列表從其父項返回到頂部?例如:

input | result 
----------------------- 
1  | null 
2  | [1] 
3  | [1] 
5  | [2, 1] 
8  | [4, 1] 
9  | [7, 3, 1] 
.... 

==================

工作查詢(但必須調用數據庫兩次)

var roleIds = session.CreateSQLQuery("SELECT Id FROM dbo.fn_get_parent_roles(:id)") 
       .SetInt32("id", roleId) 
       .List<int>(); 

Role x = null; 
var query = session.QueryOver<Role>(() => x) 
    .Where(Restrictions.In("x.RoleId", roleIds.ToArray())); 

= =================

更新時間:

var hierarchyQuery = new SQLCriterion(
       new SqlString("{alias}.RoleId IN (SELECT Id FROM dbo.fn_get_parent_roles(:id))"), 
       new object[] { roleId }, 
       new IType[] { NHibernateUtil.Int32 }); 
var results = session.QueryOver<Role>() 
      .Where(hierarchyQuery) 
      .List(); 

然後我得到這個消息:

Index was out of range. Must be non-negative and less than the size of the collection. 
Parameter name: index 

這裏充滿堆棧跟蹤

at System.ThrowHelper.ThrowArgumentOutOfRangeException() 
    at System.Collections.Generic.List`1.get_Item(Int32 index) 
    at NHibernate.Criterion.SQLCriterion.ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters) 
    at NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetWhereCondition(IDictionary`2 enabledFilters) 
    at NHibernate.Loader.Criteria.CriteriaJoinWalker..ctor(IOuterJoinLoadable persister, CriteriaQueryTranslator translator, ISessionFactoryImplementor factory, ICriteria criteria, String rootEntityName, IDictionary`2 enabledFilters) 
    at NHibernate.Loader.Criteria.CriteriaLoader..ctor(IOuterJoinLoadable persister, ISessionFactoryImplementor factory, CriteriaImpl rootCriteria, String rootEntityName, IDictionary`2 enabledFilters) 
    at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) 
    at NHibernate.Impl.CriteriaImpl.List(IList results) 
    at NHibernate.Impl.CriteriaImpl.List[T]() 
    at NHibernate.Criterion.QueryOver`1.List() 
    at NHibernate.Criterion.QueryOver`1.NHibernate.IQueryOver<TRoot>.List() 
    at At2ClaimBO.Src.Repositories.UserRepo.GetUsers(String searchStr, Int32 roleId, Int32 page) in D:\Arunsawad\At2ClaimBO\At2ClaimBO\Src\Repositories\UserRepo.cs:line 85 
    at At2ClaimBO.Src.Services.ClaimService.GetUsers(String searchStr, Int32 roleLevel, Int32 page) in D:\Arunsawad\At2ClaimBO\At2ClaimBO\Src\Services\ClaimService.cs:line 1326 
    at At2ClaimBO.Controllers.AdminController.SearchHead(String search_str, String role_id, Int32 page) in D:\Arunsawad\At2ClaimBO\At2ClaimBO\Controllers\AdminController.cs:line 259 
    at lambda_method(Closure , ControllerBase , Object[]) 
    at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) 
    at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) 
    at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) 
    at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() 
    at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) 
    at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End() 
    at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) 
    at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() 
    at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() 

回答

1

NHibernate的本身並不支持這一點 - 你將不得不使用類似的表值函數和SQL查詢:

假設您使用的是MSSQL服務器,並且支持表值函數的版本(可能是2008以後?):

SQL函數:

CREATE FUNCTION fnGetParents(@id INT) 
    RETURNS @tbl TABLE (ID INT NOT NULL) 
    AS 
BEGIN  
    ;WITH t AS (
     SELECT ParentId AS Id 
     FROM Hierarchy 
     WHERE Id = @id 
     UNION ALL 
     SELECT ParentId 
     FROM Hierarchy 
     INNER JOIN t ON t.Id = Hierarchy.Id 
    ) 
    INSERT INTO @tbl 
    SELECT DISTINCT Id FROM t 
    WHERE Id IS NOT NULL 

    RETURN; 
END 

,然後得到的結果:

session.CreateSQLQuery("SELECT Id FROM dbo.fnGetParents(:id)") 
    .SetInt32("id", id) 
    .List<int>(); 

如果你想將其包含在標準或QueryOver功能,您可以使用SQLCriteria或SQLProjection,如:

var hierarchyQuery = new SQLCriterion(
          new SqlString("{alias}.id IN (SELECT Id FROM dbo.fnGetParents(?))"), 
          new object[] {id}, 
          new[] {NHibernateUtil.Int32}); 
var results = session.QueryOver<Hierarchy>() 
      .Where(hierarchyQuery) 
      .List(); 
+0

感謝您的快速回答:) – 2014-10-05 03:49:33

+0

哦,我該如何將這個結果添加到QueryOver的Where子句中,我想要獲得具有該列表中從此函數返回的id的對象,我試過了Restrictions.In和子查詢但不是運氣:( – 2014-10-05 04:42:29

+0

我想通了,但它發送了2個分離的調用數據庫,有無論如何,我可以將它們合併成一個電話? – 2014-10-05 06:29:00