Linq到Nhibernate - 调用方法里面的选择中断IQueryable

时间:2012-08-21 16:23:10

标签: nhibernate linq-to-nhibernate

我需要基于Domain实体的业务逻辑程序集中的IQueryable。由于大量类似的实体,我想为此目的使用自动映射器。

使用:

_repository.GetList<AgentDto>()
        .Select(dto => new Agent{Login = dto.Login, Password = dto.Password})
        .Where(...).ToList();

不起作用(我无法在Where之前放置Select(另一个装配):

_repository.GetList<AgentDto>()
        .Select(dto => ToAgent(dto))
        .Where(...).ToList();

private Agent ToAgent(AgentDto dto)
    {
        return new Agent{Login = dto.Login, Password = dto.Password};
    }

例外:

System.NotSupportedException was caught
  Message=CustomerInfo.Domain.Support.Agent ToAgent(CustomerInfo.DAL.DTO.AgentDto)
  Source=NHibernate
  StackTrace:
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMemberExpression(MemberExpression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression)
       at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.Visit(Expression expression, VisitorParameters parameters)
       at NHibernate.Linq.Visitors.QueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
       at Remotion.Linq.Clauses.WhereClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
       at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
       at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
       at NHibernate.Linq.Visitors.QueryModelVisitor.Visit()
       at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
       at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
       at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
       at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
       at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
       at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
       at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
       at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
       at System.Linq.Queryable.Count[TSource](IQueryable`1 source, Expression`1 predicate)
       at CustomerInfo.BLL.Authentication.AgentManagementService.ValidateAgent(String agentLogin, String password) in D:\Projects\CustomerInfo\CustomerInfo.BLL\Authentication\AgentManagementService.cs:line 49
  InnerException: 

2 个答案:

答案 0 :(得分:4)

您需要考虑NHibernate Linq提供程序的工作原理。它无法处理你抛出的所有东西。 NHibernate的Linq提供程序将lambda表达式转换为HQL,最终转换为SQL。它只能支持有限的表达式子集。您作为表达式输入的任何内容都必须可转换为SQL并在数据库引擎本身中执行。

NHibernate Linq提供商是extensible。如果您需要使用NH Linq提供程序不支持的某些表达式,并且您认为它们可以在SQL中表示,则可以编写自己的extension

但是,你的情况非常简单。你不需要扩展NHibernate就可以了。 NHibernate Linq提供程序不支持您的表达式,但Linq对象支持。只需颠倒查询中的顺序,它应该按预期工作:

_repository.GetList<AgentDto>()
    .Where(...).ToList()
    .Select(dto => ToAgent(dto)).ToList();
.ToList()之后的

.Where()将执行NHibernate查询并返回AgentDto个对象的列表。之后的.Select方法实际上是作为Linq对象执行的 - 在内存中AgentDto个对象的列表上。

答案 1 :(得分:0)

我认为如果你只是把 Where 放在 Select 之前,你会没事的。