以下のスキーマを前提として、必要なフォームが欠落している連絡先を返すEFクエリを作成しようとしています。各連絡先には、FormTypesのコレクションに関連するContactTypeがあります。すべての連絡先は、そのContactTypeに関連するFormTypesの少なくとも1つのフォーム(ContactForm内)を持っている必要があります。
以下のlinqクエリからEFが生成するクエリは、SQL Serverに対しては機能しますが、Oracleに対しては機能しません。
var query = ctx.Contacts.Where (c => c.ContactType.FormTypes.Select (ft => ft.FormTypeID)
.Except(c => c.Forms.Select(f => f.FormTypeID)).Any());
SQL Serverに対して機能するすべてのEFクエリが、DevartのdotConnectデータプロバイダーを使用してOracleに対しても機能するように、データレイヤーをリファクタリングしているところです。
OracleがスローしているエラーはORA-00904:"Extent1"。"ContactID":無効な識別子です。
問題は、Oracleがレベル2以降のネストされたサブクエリのクエリからのテーブル列の参照をサポートしていないことです。Oracleがスローする行は、「Extent1」。「ContactID」を参照しているExcept(またはマイナス)サブクエリにあります。「Extent1」は、クエリの最上位で定義されている連絡先のエイリアスです。これは、Oracleの制限に関するDevartの説明です。
多くのクエリでこの問題を解決する方法は、SelectMany()と場合によってはJoin()を使用して、テーブル間の関係をWhere()述語からクエリの本体に移動するように書き直すことです。これにより、データベースサーバーに送信されるクエリがフラットになり、EFによって生成されるサブクエリが最小化または排除される傾向があります。 これは、左外部結合を使用して解決された同様の問題です。
列"Extent1"。"ContactID"が存在し、EFとDevartが生成するクエリの命名構文は問題ではありません。
このクエリを書き直す方法についてのアイデアは大歓迎です。目的は、OracleおよびSQLServerに対して機能する連絡先のContactTypeに必要なFormTypeのフォームが欠落している連絡先を返すクエリです。