3

Пытается переопределить Oracle10gDialect и добавить функции над и разделением. Я прочитал на hibernate.org о том, как переопределить диалект. Я использую Hibernate 4.1.7.Final и не могу обновить. Я реализовал его как указано, однако я получаю эту ошибку.Критерии спящего режима с аналитической функцией оконного анализа Oracle

 15:21:21,353 WARN SqlExceptionHelper:143 - SQL Error: 907, SQLState: 42000 
[10/8/13 15:21:21:354 CDT] 00000021 SystemOut  O ORA-00907: missing right parenthesis 

[10/8/13 15:21:21:354 CDT] 00000021 SystemOut  O 15:21:21,354 ERROR SqlExceptionHelper:144 - ORA-00907: missing right parenthesis 

Вот класс, который я строить:

package com.edmann.util; 

import org.apache.log4j.Logger; 
import org.hibernate.dialect.Oracle10gDialect; 
import org.hibernate.dialect.function.StandardSQLFunction; 

/** 
* Because i need some analytic functions i am going to extend the 
* oracle10gDialect so i can register my functions i want to use. 
* 
* @author Edward Mann 
* 
*/ 
public class Oracle10gDialectExtended extends Oracle10gDialect { 
    // get log4j handler 
    private static final Logger LOG = Logger 
      .getLogger(Oracle10gDialectExtended.class); 

    /** 
    * Override registerFunctions so that we can register the ones we want to 
    * use, then we will call the registerFunctions from the parent class. 
    * 
    */ 
    @Override 
    protected void registerFunctions() { 
     LOG.info("Trying to register custom functions"); 
     registerFunction("over", new StandardSQLFunction("over")); 
     registerFunction("partition", new StandardSQLFunction("partition")); 
     super.registerFunctions(); 
    } 
} 

Вот моя запись в моем файле hbm.xml:

<property name="rank" type="integer" formula="(ROW_NUMBER() over(partition by ENTRY_NUMBER ORDER BY ENTRY_DATE DESC))"/> 

Проблемой я имею держу зимую от добавления это_. к разделу. В теме форума hibernate, с которой я связан, последней записью был человек, имеющий ту же проблему. Я не уверен, возможно ли это с помощью Hibernate Criteria.

Спасибо за любую помощь.

Update: Я нашел мой ответ я добавил

registerKeyword("partition"); 

К моему Oracle10gDialectExtended класса в методе registerFunctions и теперь он работает, как ожидалось.

ответ

1

Так что за длинный ответ о том, как я получил это на работу. Вот как я смог использовать мою функцию ROW_NUMBER() в режиме спящего режима.

Я не знаю, будет ли кто-то еще искать что-то подобное, и ответ у меня есть только частичный. Обновление, которое я дал, позволило разделу правильно вызываться в запросе в базе данных, но я не мог использовать значение ранга, чтобы ограничить результаты. Ниже приведенные изменения кода, которые я сделал, позволили мне использовать значение ранга в запросе.

Известные ограничения

  1. Ранг кодируется как 1, я не обеспечивает способ изменить число, кроме как изменить его в коде и перекомпилировать СРК.
  2. Это работает только с setMaxResults. Поскольку вы не можете использовать значение ранга в части WHERE того же запроса, вам необходимо обернуть его и использовать в другом запросе. Мне нужно ограничение на запросы, которые я запускаю, поэтому это отлично работает для меня.
  3. Вы можете использовать только один раздел. Я не знаю, почему кто-то использовал больше одного, но я думал, что просто поставлю это там.
  4. раздел должен быть всем в нижнем регистре. если нет, это не будет соответствовать.
  5. «как» для обозначения псевдонима - это все строчные буквы. Не уверен, будет ли это когда-либо в верхнем регистре. Если это indexOf не поймает его.

В классе Oracle10gDialectExtended упоминалось выше, вы должны добавить еще два метода

/** 
* I need to override the getLimitString so that i can append the partition 
* by column on the end. If partition is not found in the string then it 
* will not be added. 
*/ 
@Override 
public String getLimitString(String sql, boolean hasOffset) { 
    // LOG.info("Using our getLimitString value"); 
    sql = sql.trim(); 
    String forUpdateClause = null; 
    boolean isForUpdate = false; 
    final int forUpdateIndex = sql.toLowerCase().lastIndexOf("for update") ; 
    if (forUpdateIndex > -1) { 
     // save 'for update ...' and then remove it 
     forUpdateClause = sql.substring(forUpdateIndex); 
     sql = sql.substring(0, forUpdateIndex-1); 
     isForUpdate = true; 
    } 
    String rank = ""; 
    if (sql.contains("partition")) { 
     rank = findRank(sql); 

    } 
    StringBuilder pagingSelect = new StringBuilder(sql.length() + 100); 
    if (hasOffset) { 
     pagingSelect.append("select * from (select row_.*, rownum rownum_ from ("); 
    } 
    else { 
     pagingSelect.append("select * from ("); 
    } 
    pagingSelect.append(sql); 
    if (hasOffset) { 
     pagingSelect.append(") row_ where rownum <= ? "); 
     pagingSelect.append(rank); 
     pagingSelect.append(") where rownum_ > ?"); 
    } 
    else { 
     pagingSelect.append(") where rownum <= ?"); 
     pagingSelect.append(rank); 
    } 

    if (isForUpdate) { 
     pagingSelect.append(" "); 
     pagingSelect.append(forUpdateClause); 
    } 

    return pagingSelect.toString(); 
} 

/** 
* Take our sql query find the partition line and pull off the hibernate 
* generated alias name. 
* 
* @param sql 
* @return String - sql with rank limit 
*/ 
private String addRank(String sql) { 
    int partition = sql.indexOf("partition"); 
    String rank = ""; 
    if (partition != -1) { 
     int start = partition; 
     int end = sql.indexOf(',', start); 
     String aliasName = end == -1 ? sql.substring(start) : sql 
       .substring(start, end); 
     int last = aliasName.indexOf("as"); 
     if (last != -1) { 
      rank = " AND "+aliasName.substring(last + 2)+ " = 1"; 
     } 
    } 
    return rank; 
} 

С учетом этих изменений я был в состоянии использовать свой ранг значение, не меняя ничего другого в моем Criteria запросе. Вывод запроса выглядит примерно так:

SELECT * FROM (SELECT ... 
    ROW_NUMBER() over(partition BY this_.ENTRY_NUMBER ORDER BY this_.ENTRY_DATE DESC) AS formula1_22_, 
...) 
WHERE rownum <= 250 AND formula1_22_ =1 

Обновлено: были сделаны изменения, потому что я не тестировал запрос смещения. Ранг был добавлен в неправильную часть запроса. Было проще взять исходный запрос getLimitString и добавить значение ранга = 1, где это необходимо.