2012-02-17 10 views
3

OracleデータベースでGrailsを使用しています。GrailsとOracleで 'リスト内の式の最大数が1000です'エラー

  • 方向
  • グループ
  • 建築現場
  • 契約
  • 検査:自分のアプリケーション内のデータのほとんどは、このような何かを(各項目は、以下のものを含む)になる階層の一部でありますユーザへ
  • 非準拠

データ可視Iユーザーの役割に応じて、方向、グループ、または建物のサイトレベルになることができる彼のアクセスに従ってフィルタリングされます。

ほとんどのシステムでlistの代わりに使用するBuildingSiteドメインクラスのlistWithSecurityメソッドを作成することで簡単に達成できました。契約のための別のlistWithSecurityメソッドを作成しました。基本的にContract.findAllByContractIn(BuildingSite.listWithSecurity)を実行します。その他のクラスでも同様です。これには、BuildingSite.listWithsecurityにすべての実際のアクセスロジックを保持するという利点があります。

問題は、システムで実際のデータを取得し始めたときに発生しました。私たちはすばやく "ora-01795リストの式の最大数は1000です"というエラーになります。十分に公正で、1000以上のリテラルのリストを渡すことは最も効率的なことではありませんので、私は各コ​​ントローラにセキュリティロジックを追放しなければならないことを意味しましたが、他の方法で試しました。

明白な方法は、(私は簡単にするために、ここで方向性レベルのアクセスを入れて)このような基準を使用するように見えた:

def c = NonConformity.createCriteria() 
def listToReturn = c.list(max:params.max, offset: params.offset?.toInteger() ?: 0) 
{ 
    inspection { 
     contract { 
      buildingSite { 
       group { 
        'in'("direction",listOfOneOrTwoDirections) 
       } 
      } 
     } 
    } 
} 

私は避けるだろう参加すると、単一のクエリを生成するために、Grailsのを期待していましたora-01795エラーが発生しましたが、各レベルの個別の問合せをコールし、結果をOracleにリテラルとして 'in'で渡して、別のレベルを問い合せているようです。言い換えれば、それはまさに私がやっていることをしているので、同じエラーが出ます。

実際には、ビットを最適化している可能性があります。それは問題を解決しているようですが、1つのレベルについてのみです。前の例では、1001件の検査でエラーは発生しませんでしたが、1001件の契約または建物のサイトで取得します。

また、findAllと1つのHQLでは、基本的に同じことをしようとしましたが、1つの方向に渡って1つのクエリでnonConformitiesを取得するステートメントです。同じこと。それは最初のレベルを解決しますが、他のレベルでも同じエラーが発生します。

私は 'in'の基準を 'または'の中の 'に'分割することでパッチを当てることができました.1000以上の長さのリテラルのリストはありませんが、それはひどく醜いコードです。 1つのfindAllBy [...]が10行以上のコードになります。そして、長期的には、非常に大量のパラメータを使用してクエリを実行しているため、パフォーマンスの問題が発生する可能性があります。

誰かがこの問題に遭遇し、よりエレガントで効率的な方法で解決しましたか?

+0

独自のクエリ/ sqlを作成し、ストアドプロシージャまたはビューに入れることも可能です。あなたが知っている、または期待がある場合は、あなたのケースでグレイルズがどのようなクエリを生成すべきか、それから試してみてください。これらのクエリは、アプリケーション/システムの非常に重要な部分になると思われます。 –

答えて

0

Juergenのコメントと同じ行で、ユーザー/ロールのアクセスルールを最も細かいレベルで平坦化するDBビューを作成することで同様の問題に近づいてきました。ビューには、ビルドサイトIDとユーザー/グループ名の2つの列だけが含まれている場合があります。したがって、ユーザーが方向レベルのアクセス権を持っている場合、セキュリティビューには、ユーザーがアクセスを許可されている方向の各子ビルディングサイトの行が1行あります。

次に、セキュリティビューにマップし、これを他のドメインクラスに結合し、ビューのuser/roleフィールドを使用してフィルタリングする読み取り専用GORMクラスを作成します。

あなたは、しかし、休止状態でいくつかの楽しみを持っている必要があるかもしれません。運が良ければ、あなたは(http://grails.1312388.n4.nabble.com/Grails-Domain-Class-and-Database-View-td3681188.htmlここではいくつかのヒント):完全GORMでこれを行うことができるでしょうhttp://grails.org/doc/latest/guide/hibernate.html

2

これは勝てないだろう任意の効率の賞を授与されましたが、1000以上のアイテムのリストを照会する必要がある場合は、オプションとして投稿すると思いました。代わりに...あなたはGroovyのCOLLATE()メソッドの使用があなたのリストを分割することができますGrailsの基準では

(このstackoverflowの質問は、「Oracleの1000 Grailsの」のためのGoogleの検索結果の一番上にあります)

def result = MyDomain.createCriteria().list { 
     'in'('id', idList) 
    } 

...この例外をスローした:

could not execute query 
org.hibernate.exception.SQLGrammarException: could not execute query 
    at grails.orm.HibernateCriteriaBuilder.invokeMethod(HibernateCriteriaBuilder.java:1616) 
    at TempIntegrationSpec.oracle 1000 expression max in a list(TempIntegrationSpec.groovy:21) 
Caused by: java.sql.SQLSyntaxErrorException: ORA-01795: maximum number of expressions in a list is 1000 
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440) 

あなたはこのようなものになってしまいます:

これの

InList> 1000個のアイテムを作成しようとしたときに、HibernateまたはGrailsがあなたのためにこれを実行しないことは残念ですが、Oracleの方言を使用しています。

このリファクタリングのトピックで、1000以上のアイテムリストにならないように、私は多くの議論に同意しますが、上記のコードは関係ありません。

関連する問題