четверг, 20 августа 2009 г.

ASP.NET + NHibernate + Oracle и Pagination

Постраничный вывод в ASP.NET + NHibernate + Oracle.
Выдергивать из базы данные постранично желание отнюдь не запретное, посему решено было его удовлетворить.

public class InsuredController : Controller
  {
    private ISessionFactory _SessionFactory;  

    private int? currentPage=0;
    private int pageSize=25;

    //...

    public ActionResult Index(int? pageNumber)
    {      
      currentPage = pageNumber??0;

      ICriteria creteria = _SessionFactory.OpenSession().CreateCriteria(typeof(Foo.FooEntity));
      
      creteria.SetFirstResult(pageSize * (int)currentPage).SetMaxResults(pageSize);
      
      ViewResult vresult = View(creteria.List<Foo.FooEntity>());
      vresult.ViewData["PageNumber"] = pageNumber;
      return vresult;
    }
}

* This source code was highlighted with Source Code Highlighter.


Все бы хорошо, но дальше 0 страницы данные не возвращаются, а все потому что в базу уходит запрос
SELECT  *
 FROM  (SELECT  this_.ID AS ID1_0_0_,
          this_.CREATE_DATE AS CREATE2_0_0_,
          this_.DISABLE_DATE AS DISABLE3_0_0_,
          this_.EDIT_DATE AS EDIT4_0_0_,
          this_.EXCHANG_STAT AS EXCHANG5_0_0_
      FROM  FOO this_)
WHERE  ROWNUM BETWEEN 25 AND 75


* This source code was highlighted with Source Code Highlighter.


А вот оно что - BETWEEN vs ROWNUM.
А в школьном курсе оракловой физики четко написано что ROWNUM - это псевдостолбец, значение которого присваивается строке уже после выполнения предикатов запроса, но перед выполнением сортировок и агрегирований. В то же время оператор BETWEEN ограничивает выборку по столбцу значение которого еще не было присвоено, те равно NULL. А все операции сравнения чего либо с значением NULL = FALSE. Вот и получаем пустой результат.

Решение этой проблемы простое - заменить в конфиге значение своейства dialect - NHibernate.Dialect.OracleDialect на NHibernate.Dialect.Oracle10gDialect или NHibernate.Dialect.Oracle9iDialect

Результирующий запрос:
SELECT  *
 FROM  (SELECT  row_.*, ROWNUM rownum_
      FROM  (SELECT  this_.ID AS ID1_0_0_,
               this_.CREATE_DATE AS CREATE2_0_0_,
               this_.DISABLE_DATE AS DISABLE3_0_0_,
               this_.EDIT_DATE AS EDIT4_0_0_,
               this_.EXCHANG_STAT AS EXCHANG5_0_0_
           FROM  FOO this_) row_
      WHERE  ROWNUM <= :p0)
WHERE  rownum_ > :p1


* This source code was highlighted with Source Code Highlighter.

Комментариев нет: