NHibernate.QueryException:无法使用WebApi + ODaa解析属性

时间:2013-07-02 19:45:41

标签: nhibernate asp.net-mvc-4 fluent-nhibernate asp.net-web-api odata

当我在我的网址上使用过滤器作为GET /api/modalidades?$orderby=Nome&$select=Nome,Id时,会显示错误!

软件包:

  

FluentNHibernate 1.3.0.733
  NHibernate 3.3.3.4000
  Microsoft.AspNet.WebApi 5.0.0-rtm-130624
  Microsoft.AspNet.WebApi.Client 5.0.0-rtm-130624
  Microsoft.AspNet.WebApi.Core 5.0.0-rtm-130624
  Microsoft.AspNet.WebApi.OData 5.0.0-rtm-130624
  Microsoft.AspNet.WebApi.Web ... 5.0.0-rtm-130624

代码

public class Modalidade : EntityNome
{ }
public abstract class EntityNome : IEntity
{
    public virtual int Id { get; protected internal set; }

    [StringLength(80)]
    [Required]
    public virtual string Nome { get; set; }
}
public interface IEntity : IKeyed<int>
{
}
public interface IKeyed<T> where T : struct
{
    T Id { get; }
}

网络

WebApiConfig.css

public static void Register(HttpConfiguration config)
{
    var modelBuilder = new ODataConventionModelBuilder();

    modelBuilder.EntitySet<Modalidade>("modalidades");
    modelBuilder.Entity<Modalidade>()
        .DerivesFrom<EntityNome>()
        .Property(p => p.Id);

    var model = modelBuilder.GetEdmModel();

    config.Routes.MapODataRoute(routeName: "OData", routePrefix: "api", model: model);

    config.EnableQuerySupport();

    var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
    var enumConverter = new StringEnumConverter();
    jsonFormatter.SerializerSettings.Converters.Add(enumConverter);

    config.Formatters.Remove(config.Formatters.XmlFormatter);
    var jqueryFormatter = config.Formatters.FirstOrDefault(x => x.GetType() == typeof(JQueryMvcFormUrlEncodedFormatter));
    config.Formatters.Remove(config.Formatters.XmlFormatter);
    config.Formatters.Remove(config.Formatters.FormUrlEncodedFormatter);
    config.Formatters.Remove(jqueryFormatter);
    config.Formatters.JsonFormatter.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
}

控制器

public class baseApiController<T> : EntitySetController<T, int>
    where T : class, IEntity
{
    public IRepository<T> Repositorio { get; private set; }

    public baseApiController(IRepository<T> repositorio)
    {
        Repositorio = repositorio;
    }

    [Queryable(AllowedQueryOptions = AllowedQueryOptions.All, PageSize = 20)]
    public override IQueryable<T> Get()
    {
        return Repositorio.All();
    }

    [HttpGet, Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    protected override T GetEntityByKey(int key)
    {
        return Repositorio.Get(key);
    }
}

[Authorize]
public class modalidadesController : baseApiController<Modalidade>
{
    public modalidadesController(IModalidadeRepository repositorio)
        : base(repositorio)
    { }
}

错误

如果没有应用过滤器,一切正常。但是当应用过滤器时,会生成错误!

  

GET / api / modalidades?$ orderby = Nome&amp; $ select = Nome,Id HTTP / 1.1
  主持人:localhost:49971
  缓存控制:无缓存

{
    "odata.error": {
        "code": "",
        "message": {
            "lang": "en-US",
            "value": "An error has occurred."
        },
        "innererror": {
            "message": "Exception has been thrown by the target of an invocation.",
            "type": "System.Reflection.TargetInvocationException",
            "stacktrace": "   at System.Web.Http.ApiController.<InvokeActionWithExceptionFilters>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()",
            "internalexception": {
                "message": "could not resolve property: class of: CreditoImobiliarioBB.Model.Modalidade [.Take[System.Web.Http.OData.Query.Expressions.SelectExpandWrapper`1[[CreditoImobiliarioBB.Model.Modalidade, CreditoImobiliarioBB.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]](.Select[CreditoImobiliarioBB.Model.Modalidade,System.Web.Http.OData.Query.Expressions.SelectExpandWrapper`1[[CreditoImobiliarioBB.Model.Modalidade, CreditoImobiliarioBB.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]](.ThenBy[CreditoImobiliarioBB.Model.Modalidade,System.Int32](.OrderBy[CreditoImobiliarioBB.Model.Modalidade,System.String](NHibernate.Linq.NhQueryable`1[CreditoImobiliarioBB.Model.Modalidade], Quote(($it, ) => ($it.Nome)), ), Quote(($it, ) => ($it.Id)), ), Quote((, ) => (new SelectExpandWrapper`1()444fb09a-b4c8-43e1-b1f6-d469f9da76eanew NamedPropertyWithNext`1()IdEqual(, NULL) ? NULL : Convert(.Id)new NamedProperty`1()IsType(, CreditoImobiliarioBB.Model.EntityNome) ? Nome : NULLEqual(, NULL) ? NULL : IsType(, CreditoImobiliarioBB.Model.EntityNome) ? TypeAs().Nome : NULL)), ), p8, )]",
                "type": "NHibernate.QueryException",
                "stacktrace": "   at NHibernate.Persister.Entity.AbstractPropertyMapping.ToType(String propertyName)\r\n   at NHibernate.Persister.Entity.AbstractEntityPersister.ToType(String propertyName)\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.FromElementType.GetPropertyType(String propertyName, String propertyPath)\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.FromElement.GetPropertyType(String propertyName, String propertyPath)\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.DotNode.GetDataType()\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.DotNode.PrepareLhs()\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.DotNode.Resolve(Boolean generateJoin, Boolean implicitJoin, String classAlias, IASTNode parent)\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.FromReferenceNode.Resolve(Boolean generateJoin, Boolean implicitJoin, String classAlias)\r\n   at NHibernate.Hql.Ast.ANTLR.Tree.FromReferenceNode.Resolve(Boolean generateJoin, Boolean implicitJoin)\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.Resolve(IASTNode node)\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.expr()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.exprOrSubquery()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.comparisonExpr()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.logicalExpr()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.caseExpr()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.arithmeticExpr()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.selectExpr()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.selectExprList()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.selectClause()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.unionedQuery()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.query()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.selectStatement()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.statement()\r\n   at NHibernate.Hql.Ast.ANTLR.HqlSqlTranslator.Translate()\r\n   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Analyze(String collectionRole)\r\n   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2 replacements, Boolean shallow, String collectionRole)\r\n   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Compile(IDictionary`2 replacements, Boolean shallow)\r\n   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)\r\n   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)\r\n   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)\r\n   at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)\r\n   at Remotion.Linq.QueryableBase`1.GetEnumerator()\r\n   at System.Web.Http.OData.Query.ODataQueryOptions.LimitResults[T](IQueryable`1 queryable, Int32 limit, Boolean& resultsLimited)"
            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

查询的$ select部分令人不安。我们还没有试过让$ select和$ expand使用除Linq2Objects和Entityframework之外的任何东西。我们生成的用于获得$ select和$ expand的表达式并且以有效的方式使用Entityframework是非常重要的。

那就是说,你的问题的一个解决方案是采用ODataQueryOptions并在部分中应用查询。在数据库中应用$ filter,$ orderby,$ skip,$ top,然后在第一步之后执行ToList(),在内存中应用$ select和$ expand。

我将继续使用nhibernate来查看我们是否可以改进表达式生成以使此方案正常工作。

答案 1 :(得分:0)

尝试将EnsureStableOrdering = false添加到QueryableAttribute

[Queryable(EnsureStableOrdering = false, AllowedQueryOptions = AllowedQueryOptions.All, PageSize = 20)]
public override IQueryable<T> Get()