2012-01-02 120 views
1

我是相當新的具有來自一個EF背景,我用下面的查詢掙扎:Linq query 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(); 

此查詢的目的是允許用戶在篩選的兩個查詢使用兩個Build ??? Specification函數構建的參數並返回結果集。可能有許多錄取記錄,我只希望每個患者對象有一個PatientSearchResultModel,錄取對象是錄取日期中最新的一個。

這些對象來自nHibernate,它保持返回一個不支持的異常。 Patient和Admissions之間也有一個關聯:Patient.Admissions,但我無法弄清楚如何添加查詢過濾器從函數Build ??? Specifications返回。

如果有人能指引我正確的方向,我會很感激;我是否在nHibernate中針對Linq提供程序實現並需要移至Criteria或是我的Linq查詢?

如果有人在這方面有很好的書籍或其他學習材料的任何鏈接或建議,也會很有幫助。

回答

3

我看到一些潛在的問題:

  1. 如果你正在使用NHibernate 2.x的+ Linq2NHibernate明確連接一樣,不支持;在其他版本中,他們只是被認爲是一種氣味。
  2. 我不認爲NHibernate的支持在選擇條款調用參數化的構造
  3. 我很肯定NHibernate的不支持調用在選擇拉姆達

我建議使用的lambda語法和SelectMany以實例方法緩解潛在的加入問題。分數#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

謝謝傑夫爲此;有一些小的調整,它工作得很好! – 2012-01-06 12:57:16

+0

不是'AsEnumerable'是否可以撤銷映射中指定的任何連接或惰性性能增益? 'AsEnumerable'會產生選擇N + 1混亂嗎? – 2012-04-30 03:21:47

+1

我不明白爲什麼會這樣。 AsEnumerable將強制執行查詢的查詢,但該行爲通過ToList存在於原始代碼片段中。 AsEnumerable本身並不會導致像N + 1查詢這樣的愚蠢事情。 – JeffreyABecker 2012-05-07 13:39:41

0

將查詢劃分爲幾部分,並檢查哪部分運行,哪些不運行。

我認爲這是不支持Linq到nHibernate。

我會推薦使用別的東西,因爲它太簡單了,太過於成熟而且功能更少。

0

與大多數流行的LINQ到數據庫查詢提供商,NHibernate的會嘗試將整個查詢轉換爲SQL語句,對數據庫運行。這要求查詢的所有元素都可以用你正在使用的SQL風格表達。

在您的查詢中,select new語句無法用SQL表示,因爲您正在調用PatientSearchResultModel類的構造函數,並正在調用GetPhaseTypeModel方法。

您應該重組查詢以表達您想要在SQL數據庫上執行的操作,然後調用AsEnumerable()來強制查詢的其餘部分在內存中進行評估。在這個調用之後,你可以調用你的類的構造函數和任何.NET方法,它們將作爲本機代碼執行。

0

該查詢過於複雜,無法用Linq來描述。它最終會給出錯誤的結果(如果Patient有多個入場記錄,結果會有重複的入場記錄)。

我看到的解決方案分爲兩步:

1)在開發階段,使用內存中查詢。所以,首先使用ToList()(此時查詢db)。一些謂詞(像MRN,First,Last這樣的患者過濾器)可以在此階段使用。 然後在內存中進行搜索。不是性能,而是工作解決方案。將其標記爲重構以稍後進行優化。 2)最後,使用NHibernate IQuery(ISQLQuery)並手動構建sql查詢,以確保它能夠按預期工作,並且在SQL Server端足夠快地工作。這只是只讀查詢,根本不需要Nhibernate查詢引擎(Linq to Nhibernate)。