Question

( Disclaimer:.. J'ai changé / obscurcie certains des noms variables / tables / colonne ici pour des raisons de sécurité S'il vous plaît pardonnez-moi si quelque chose semble un peu hors)

Je construis un front-end à la base de données Oracle, et je suis en train d'obtenir des données paginée. En dehors de la pagination, le code suivant SubSonic 2.2 me donne ce que je veux, dans l'ordre que je veux:

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

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

Cela donne l'instruction SQL suivante:

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

Alors je tente d'introduire la pagination:

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

Et il efface mes clauses WHERE et ORDER BY:

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

Je suis tout nouveau à subsonique, donc je ne sais pas si c'est un bug, ou je fais tout simplement pas le meilleur moyen, ou si Oracle exige que cela soit fait dans un autre, plus centrée sur Oracle façon. (Oracle semble exiger de tout.)

Ce que je veux, dans le cas où il est pas évident, est chaque page suivante pour inclure les 10 plus récemment créés, les dossiers non handicapés. Comment puis-je faire en subsonique 2.2?

Était-ce utile?

La solution

Il semble que votre requête ne génère pas la même SQL que le courant Oracle Data Provider SubSonic devrait. Voici le code correspondant (à partir de la ligne 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;

Peut-être une mise à jour source de courant ferait l'affaire. S'il y a quelque chose de mal avec le fournisseur actuel, vous pouvez le comparer à la SqlDataProvider pour obtenir des conseils quant à ce qui pourrait être le problème.

Autres conseils

Je suis dans un environnement utilisant NET 2.0 et Oracle 9i R2 et je suis tombé sur le même problème. J'utilise SubSonic 2.2.

J'ai téléchargé la source de GitHub et ce que je trouve:

Le code cité par @ranomore (OracleDataProvider.GetSelectSql ()) est appelée uniquement lorsque vous utilisez l'objet SubSonic.Query. Depuis l'OP et moi-même utiliser l'objet Select qui est dérivé de l'objet SubSonic.SqlQuery plus récent et plus puissant, OracleDataProvider.GetSelectSql () ne sera jamais appelé. Au lieu de cela, OracleGenerator.BuildPagedSelectStatement () est appelé et génère le SQL que vous voyez affiché par l'OP. Ce code est buggé car il ajoute jamais WHERE et ORDER BY clauses à la requête qu'elle génère finalement la pagination.

Je remplacé le contenu de BuildPagedSelectStatement () avec quelque chose basé sur 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();
}

Ce qui précède a fonctionné pour moi. Espérons que cela aide les autres!

Oracle serait très bien avec la requête Top-N si le SQL interne consisterait en la première déclaration (y compris le cas et l'ordre par).

Alors, je dirais qu'il n'y a aucune raison spécifique Oracle de les omettre.

Jamais utilisé subsonique, ne sais pas si vous avez besoin de le faire différent là-bas.

Performance sage, un index sur DISABLED_DATE, CREATED_DATE devrait faire l'affaire (voir: http://blog.fatalmind.com/2010/07/30/analytic-top-n-queries/ ).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top