2012-01-02 9 views
1

は、EFの背景から来て、私は次のクエリで苦労しています:Linqクエリnhibernate;私はNHibernateはにかなり新しいですサポートされていない例外

_patientSearchResultModel = (from patient in _patientRepository.Query(patientSearch.BuildPatientSpecification()) 
          join admission in _admissionRepository.Query(patientSearch.BuildAdmissionSpecification()) 
           on patient.Id equals admission.Patient.Id 
          orderby admission.AdmissionDate 
          select new PatientSearchResultModel(patient.Id, 
           admission.Id, 
           false, 
           _phaseTypeMapper.GetPhaseTypeModel(admission.PhaseType), 
           patient.Last, patient.First, 
           admission.InPatientLocation, 
           admission.AdmissionDate, 
           admission.DischargeDate, 
           admission.RRI, 
           null, 
           admission.CompletionStatus, 
           admission.FollowupStatus)).ToList(); 

このクエリの意図は、ユーザーが上の2つのクエリをフィルタリングできるようにすることです2つのBuild ??? Specification関数を使用して構築されたパラメータを返し、結果セットを返す。入院記録が多数ある可能性があり、患者オブジェクトごとに1つのPatientSearchResultModelが好きであり、入場日は入場日によって最新のものになります。

これらのオブジェクトはnHibernateからのもので、サポートされていない例外が返されます。 PatientとAdmissionsの間には関連があります:Patient.Admissionsでも、ビルドの仕様から返されるクエリフィルタの追加方法を理解できませんでした。

誰かが私を正しい方向に向けることができたら本当に感謝しています。私はここでnHibernateのLinqプロバイダの実装と反対し、Criteriaに移動する必要がありますか、それは私のLinqクエリですか?

誰かがこのエリアの良い本や他の学習資料のリンクや提案を持っている人は、本当に役に立ちます。

答えて

3

私はいくつかの潜在的な問題を参照してください。あなたはNHibernateの2.xの+明示的なLinq2NHibernateを使用している場合

  1. がサポートされていないことのように参加します。他のバージョンでは、それらは単ににおいとみなされています。私はNHibernateのは、私はラムダ構文を使用してお勧めする選択ラムダ

でインスタンスメソッドを呼び出すとSelectManyにはサポートしていません非常に確信してNHibernateのは

  • SELECT句にパラメータ化されたコンストラクタを呼び出しをサポートしていと思ういけない
  • 潜在的な参加の問題を緩和する。ポイント#2 &#3は、匿名タイプに投影し、AsEnumerableを呼び出してモデルタイプに投影することで解決できます。

    var patientSpec = patientSearch.BuildPatientSpecification(); 
    var admissionSpec = patientSearch.BuildAdmissionSpecification(); 
    _patientSearchResultModel = _patientRepository.Where(patientSpec) 
        .SelectMany(p=>p.Admissions).Where(admissionSpec) 
        .Select(a=> new { 
         PatientId = a.Patient.Id, 
         AdminssionId = a.Id, 
         a.PhaseType, 
         a.Patient.Last, 
         a.Patient.First, 
         a.InPatientLocation, 
         a.AdmissionDate, 
         a.DischargeDate, 
         a.RRI, 
         a.CompletionStatus, 
         a.FollowupStatus 
        }).AsEnumerable() 
        .Select(x=> new PatientSearchResultModel(x.PatientId, x.AdmissionId ...)) 
        .ToList(); 
    
  • +0

    ありがとうございました。それは素晴らしい仕事の小さな調整のカップルで! –

    +0

    'AsEnumerable'は、マッピングで指定された結合や遅延パフォーマンスの向上を元に戻しませんか? AsEnumerableは選択されたN + 1混乱の権利を作成する予定ですか? –

    +1

    私はそれがなぜか分かりません。 AsEnumerableはクエリの評価と実行を強制しますが、その動作はToListを介して元のスニペットにあります。 AsEnumerableはN + 1クエリのような愚かなことを引き起こしません。 – JeffreyABecker

    0

    クエリを部分に分割し、実行する部分と実行しない部分を確認します。

    これは、select new ...がLinqからnHibernateに対応していないということです。

    真剣に使用するにはあまりにも面白くて機能が少ないので、何かを使用することをおすすめします。

    0

    最も人気のあるLINQツーデータベースクエリプロバイダと同様に、NHibernateのは、データベースに対して実行するSQL文に全体クエリを翻訳しようとします:
    は全体的に私は次のようにコードを再構築することをお勧めしたいです。これには、クエリのすべての要素が使用しているSQLの味で表現することが可能である必要があります。

    PatientSearchResultModelクラスのコンストラクタを呼び出してGetPhaseTypeModelメソッドを呼び出しているため、select newステートメントをSQLで表すことはできません。

    SQLデータベースで実行する内容を表現するようにクエリを再構成し、残りのクエリをメモリ内で評価するようにするには、AsEnumerable()を呼び出します。その呼び出しの後、クラスのコンストラクタと.NETメソッドを呼び出すと、ネイティブコードとして実行されます。

    0

    このクエリはLinqを使って説明するには複雑すぎます。最終的に間違った結果が出るでしょう(もし患者が複数の入院記録を持っていれば、結果は重複するでしょう)。開発段階では

    1)は、メモリ内のクエリを使用します。

    は、私は解決策のための2つの手順を参照してください。だから、ToList()を最初に使って(この時点でdbを問い合わせる)患者を取る。この段階では、MRN、First、Lastのような述語(Patient filter)を使用できます。 そして、メモリ内を検索します。パフォーマンスではなく、実用的なソリューションです。後で最適化するためにリファクタのマークを付けます。

    2)最後に、NHibernate IQuery(ISQLQuery)を使用してSQLクエリを手動でビルドし、SQL Server側で十分に速く動作することを確認します。これは単なる読み込み専用のクエリであり、Nhibernateクエリエンジン(LinqからNhibernate)はまったく必要ありません。

    関連する問題