简体   繁体   English

Linq查询nhibernate; 不支持的例外

[英]Linq query nhibernate; not supported exception

I'm fairly new to nHibernate having come from an EF background and I'm struggling with the following query : 我对来自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();

The intent of this query is to allow users to filter the two queries on parameters built up using the two Build???Specification functions and return the resultset. 此查询的目的是允许用户过滤使用两个Build ???规范函数构建的参数的两个查询并返回结果集。 There could be many admission records and I would only like one PatientSearchResultModel per patient object, with the admission object being the newest one by Admission Date. 可能有许多录取记录,我只想为每个患者对象一个PatientSearchResultModel,其中录取对象是录取日期的最新录像对象。

These objects are coming from nHibernate and it keeps return a Not Supported exception. 这些对象来自nHibernate,它会保持返回不支持的异常。 There is also an association between Patient and Admissions thus : Patient.Admissions but i couldn't figure out how to then add the query filters return from the function Build???Specifications. 因此,患者和入院之间也存在关联:Patient.Admissions但我无法弄清楚如何从功能Build ???规范中添加查询过滤器返回。

I'd be really grateful if someone could point me in the right direction; 如果有人能指出我正确的方向,我真的很感激; am I up against the Linq provider implementation here in nHibernate and need to move to Criteria or is it my Linq query ? 我是否反对nHibernate中的Linq提供程序实现,需要转移到Criteria还是我的Linq查询?

If anyone has any links or suggestions for good books or other learning materials in this area that would also be really helpful too. 如果有人在这个领域有任何关于好书或其他学习材料的链接或建议,那也是非常有帮助的。

I see several potential problems: 我看到几个潜在的问题:

  1. If you're using NHibernate 2.x + Linq2NHibernate explicit joins like that are not supported; 如果您正在使用NHibernate 2.x + Linq2NHibernate,则不支持这样的显式连接; in other versions they're just considered a smell. 在其他版本中,它们只是被认为是一种气味。
  2. I dont think NHibernate supports calling parameterized constructors in select clauses 我不认为NHibernate支持在select子句中调用参数化构造函数
  3. I'm very sure NHibernate does not support calling instance methods in the select lambda 我非常确定NHibernate不支持在select lambda中调用实例方法

I'd suggest using the lambda syntax and SelectMany to alleviate potential join issues. 我建议使用lambda语法和SelectMany来缓解潜在的连接问题。 Points #2 & #3 can be solved by projecting into an anonymous type, calling AsEnumerable then projecting into your model type. 点#2和#3可以通过投射到匿名类型来解决,调用AsEnumerable然后投射到您的模型类型中。
Overall I'd suggest restructuring your code like: 总的来说,我建议重组您的代码,如:

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();

Divide your query into parts and check which part runs and which doesn't. 将您的查询划分为多个部分,并检查哪个部分运行,哪个部分不运行。

My take on this is that select new ... is not supported in Linq to nHibernate. 我对此的看法是Linq对nHibernate不支持select new ...

I would recomend using something else, because it is simply too imature and feature-less to use seriously. 我会建议使用别的东西,因为它太过不成熟,而且没有严格使用的功能。

As with most popular LINQ-to-Database query providers, NHibernate will try to translate the whole query into a SQL statement to run against the database. 与大多数流行的LINQ-to-Database查询提供程序一样,NHibernate将尝试将整个查询转换为针对数据库运行的SQL语句。 This requires that all elements of your query are possible to express in the SQL flavour you're using. 这要求查询的所有元素都可以在您正在使用的SQL风格中表达。

In your query, the select new statement cannot be expressed in SQL, because you're making a call to the constructor of your PatientSearchResultModel class and are making a call to a GetPhaseTypeModel method. 在您的查询中, select new语句不能用SQL表示,因为您正在调用PatientSearchResultModel类的构造函数并调用GetPhaseTypeModel方法。

You should restructure your query to express what you want to execute on the SQL database, then call AsEnumerable() to force the remainder of the query to be evaluated in-memory. 您应该重新构建查询以表达要在SQL数据库上执行的内容,然后调用AsEnumerable()以强制在内存中计算查询的其余部分。 After that call, you can call the constructor of your class and any .NET methods, and they will be executed as native code. 在调用之后,您可以调用类的构造函数和任何.NET方法,它们将作为本机代码执行。

This query is too complex to describe it using Linq. 此查询过于复杂,无法使用Linq进行描述。 It would give wrong result finally (if Patient has more than one admission records, result would have duplicate entries). 它最终会给出错误的结果(如果患者有多个录取记录,结果将有重复的条目)。

I see two steps for solution: 我看到两个解决方案的步骤:

1) At development stage, use in-memory query. 1)在开发阶段,使用内存中查询。 So, take Patients using ToList() first (query db at this moment). 所以,先让患者使用ToList()(此时查询db)。 Some predicates (Patient filter like MRN, First, Last) could be used at this stage. 在此阶段可以使用一些谓词(像MRN,First,Last这样的患者过滤器)。 And then do search in-memory. 然后在内存中搜索。 Not performance, but working solution. 不是性能,而是工作解决方案。 Mark it for refactor to optimize later. 将其标记为重构以便稍后进行优化。

2) Finally, use NHibernate IQuery (ISQLQuery) and build sql query manually to make sure it would work as expected and work fast enough on SQL Server side. 2)最后,使用NHibernate IQuery(ISQLQuery)并手动构建sql查询,以确保它能够按预期工作并在SQL Server端运行得足够快。 This is just read-only query and do not require Nhibernate query engine (Linq to Nhibernate) at all. 这只是只读查询,根本不需要Nhibernate查询引擎(Linq到Nhibernate)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM