Pregunta

( exención de responsabilidad:.. cambié / ofuscado algunos de los nombres de las variables / tabla / columna aquí por razones de seguridad Por favor, perdóname si algo se ve un poco apagado)

Estoy construyendo un front-end de base de datos Oracle 10g, y yo estoy tratando de obtener datos paginado. Aparte de paginación, el siguiente código SubSonic 2.2 me da lo que quiero, en el orden que quiero que:

var q = new Select()
  .From(AppDb.MyTable.Schema)
  .Where(AppDb.MyTable.DisabledDateColumn).IsNull()
  .OrderDesc(AppDb.MyTable.CreatedDateColumn.ColumnName)

System.Console.Out.Writeline(q.BuildStatement());

Esto produce el siguiente SQL:

SELECT
    MYSCHEMA.MYTABLE.ID,
    MYSCHEMA.MYTABLE.DISABLED_DATE
FROM
    MYSCHEMA.MYTABLE
WHERE
    MYSCHEMA.MYTABLE.DISABLED_DATE IS NULL
ORDER BY
    CREATED_DATE DESC

Entonces trato de introducir paginación:

var q = new Select()
  .From(AppDb.MyTable.Schema)
  .Where(AppDb.MyTable.DisabledDateColumn).IsNull()
  .OrderDesc(AppDb.MyTable.CreatedDateColumn.ColumnName)
  .Paged(0, 10);

Y se borra mi WHERE y ORDER BY cláusulas:

SELECT * FROM (
    SELECT
        MYSCHEMA.MYTABLE.ID,
        MYSCHEMA.MYTABLE.DISABLED_DATE,
        ROWNUM as row_number
    FROM
        MYSCHEMA.MYTABLE
)
WHERE
    row_number BETWEEN 1 AND 10

Soy nuevo a subsónico, así que no sé si eso es un error, o que no estoy haciendo de la manera preferida, o si Oracle exige que esto se haga de una manera diferente, más centrada en Oracle camino. (Oracle parece demandar la de todo.)

Lo que yo quiero, en caso de que no es evidente, es cada página siguiente para incluir los 10 siguientes más recientemente creadas-registros, no discapacitados. ¿Cómo puedo hacer esto en SubSonic 2.2?

¿Fue útil?

Solución

Parece que la consulta no está generando el mismo SQL como la corriente Oracle Data Provider para SubSonic debería. Aquí está el código correspondiente (que comienza en la línea 852):

    if(qry.PageIndex < 0)
        query = String.Format("{0} {1} FROM {2}.{3} {4} {5}",select ,columns, table.SchemaName, table.Name, where, order);
    else
    {
        int start = qry.PageIndex * qry.PageSize;
        int end = (qry.PageIndex + 1) * qry.PageSize;

        const string cteFormat =
                    "WITH pagedtable AS (SELECT {0}, ROW_NUMBER () OVER ({1}) AS rowindex FROM {2}.{3} {4}) SELECT {5}, rowindex FROM pagedtable WHERE rowindex >= {6} AND rowindex < {7} ORDER BY rowindex";
        query = string.Format(cteFormat, columns, order,table.SchemaName, table.Name, where, columns.Replace(table.Name + ".", String.Empty), start, end);
    }
    return query;

Tal vez una actualización de fuente de corriente haría el truco. Si hay algo mal con el proveedor real, que se puede comparar a la SQLDataProvider en busca de pistas sobre lo que podría ser el problema.

Otros consejos

Estoy en un entorno utilizando .NET 2.0 y Oracle 9i R2 y me encontré con el mismo problema exacto. Estoy usando SubSonic 2.2.

He descargado la fuente de GitHub y esto es lo que encontré:

El código citado por @ranomore (OracleDataProvider.GetSelectSql ()) sólo se llama cuando se utiliza el objeto SubSonic.Query. Desde el PO y el mismo uso Seleccione el objeto que se deriva del objeto SubSonic.SqlQuery más nuevo y más potente, OracleDataProvider.GetSelectSql () no es llamado. En su lugar, OracleGenerator.BuildPagedSelectStatement () es llamada y genera el SQL que se ve publicado por la OP. Este código está libre de errores, ya que nunca se añade el WHERE y ORDER BY cláusulas para la consulta de paginación en última instancia genera.

I reemplazó el contenido de BuildPagedSelectStatement () con algo basado en ANSISqlGenerator.BuildSelectStatement ():

public override string BuildPagedSelectStatement()
{
    int startnum = query.PageSize * query.CurrentPage + 1;
    int endnum = query.PageSize * query.CurrentPage + query.PageSize;
    string orderBy = String.Empty;

    if (this.query.OrderBys.Count > 0)
        orderBy = GenerateOrderBy();

    //The ROW_NUMBER() function in Oracle requires an ORDER BY clause.
    //In case one is not specified, we need to halt and inform the caller.
    if(orderBy.Equals(String.Empty))
        throw new ArgumentException("There is no column specified for the ORDER BY clause", "OrderBys");

    System.Text.StringBuilder sql = new System.Text.StringBuilder();

    //Build the command string
    sql.Append("WITH pagedtable AS (");
    sql.Append(GenerateCommandLine());

    //Since this class is for Oracle-specific SQL, we can add a hint
    //which should help pagination queries return rows more quickly.
    //AFAIK, this is only valid for Oracle 9i or newer.
    sql.Replace("SELECT", "SELECT /*+ first_rows('" + query.PageSize + "') */");

    sql.Append(", ROW_NUMBER () OVER (");
    sql.Append(orderBy);
    sql.Append(") AS rowindex ");
    sql.Append(Environment.NewLine);
    sql.Append(GenerateFromList());
    sql.Append(GenerateJoins());

    sql.Append(GenerateWhere());

    if (query.Aggregates.Count > 0)
    {
        sql.Append(GenerateGroupBy());
        sql.Append(Environment.NewLine);
        sql.Append(GenerateHaving());
    }

    sql.Append(") SELECT * FROM pagedtable WHERE rowindex >= ");
    sql.Append(startnum);
    sql.Append(" AND rowindex < ");
    sql.Append(endnum);
    sql.Append(" ORDER BY rowindex");

    return sql.ToString();
}

Lo anterior trabajó para mí. Espero que esto ayuda a los demás!

Oracle estaría bien con la consulta Top-N si el SQL interior consistiría en la primera declaración (incluyendo dónde y el orden por).

Por lo tanto, yo diría que no hay ninguna razón específica de Oracle omitirlos.

Nunca utiliza subsónico, no sé si lo que necesita hacer es diferente allí.

En cuanto al rendimiento, un índice en DISABLED_DATE, CREATED_DATE debe hacer el truco (ver: http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/ ).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top