Linq查询nhibernate;不支持的例外

时间:2012-01-02 17:53:08

标签: c# linq nhibernate

我对来自EF背景的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 ???规范函数构建的参数的两个查询并返回结果集。可能有许多录取记录,我只想为每个患者对象一个PatientSearchResultModel,其中录取对象是录取日期的最新录像对象。

这些对象来自nHibernate,它会保持返回不支持的异常。患者和入院之间也有一个关联:Patient.Admissions但我无法弄清楚如何从函数Build ???规范中添加查询过滤器返回。

如果有人能指出我正确的方向,我真的很感激;我是否反对nHibernate中的Linq提供程序实现,需要转移到Criteria还是我的Linq查询?

如果有人在这个领域有任何关于好书或其他学习材料的链接或建议,也会非常有帮助。

4 个答案:

答案 0 :(得分:4)

我发现了几个潜在的问题:

  1. 如果您正在使用NHibernate 2.x + Linq2NHibernate不支持这样的显式连接;在其他版本中,它们只是被认为是一种气味。
  2. 我不认为NHibernate支持在select子句中调用参数化构造函数
  3. 我非常确定NHibernate不支持在select lambda中调用实例方法
  4. 我建议使用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();
    

答案 1 :(得分:0)

将您的查询划分为多个部分并检查哪个部分运行,哪个部分不运行。

我对此的看法是,Linq对nHibernate不支持select new ...

我会建议使用别的东西,因为它太过不成熟,而且没有严格使用的功能。

答案 2 :(得分:0)

与大多数流行的LINQ-to-Database查询提供程序一样,NHibernate将尝试将整个查询转换为SQL语句以针对数据库运行。这要求查询的所有元素都可以用您正在使用的SQL风格表达。

在您的查询中,select new语句无法在SQL中表达,因为您正在调用PatientSearchResultModel类的构造函数并正在调用GetPhaseTypeModel方法

您应该重新构建查询以表达要在SQL数据库上执行的内容,然后调用AsEnumerable()以强制在内存中评估查询的其余部分。在调用之后,您可以调用类的构造函数和任何.NET方法,它们将作为本机代码执行。

答案 3 :(得分:0)

此查询过于复杂,无法使用Linq对其进行描述。它最终会给出错误的结果(如果患者有多个录取记录,结果将有重复的条目)。

我看到了解决方案的两个步骤:

1)在开发阶段,使用内存中查询。所以,先让患者使用ToList()(此时查询db)。在此阶段可以使用一些谓词(像MRN,First,Last这样的患者过滤器)。 然后在内存中搜索。不是性能,而是工作解决方案。将其标记为重构以便稍后进行优化。

2)最后,使用NHibernate IQuery(ISQLQuery)并手动构建sql查询,以确保它能够按预期工作并在SQL Server端运行得足够快。这只是只读查询,根本不需要Nhibernate查询引擎(Linq to Nhibernate)。