c# - EntitySetController $expand 和 $select 不工作

标签 c# asp.net-web-api odata

我正在尝试使用 EntitySetController 提供的 OData 获取表格的结果页面。但是,我对 $select$expand 的所有请求都失败了。有什么想法吗?

我正在使用 Entity Framework v6 和 System.Web.Http.OData v5。

我的实体:

public partial class Contact : BaseEntity
{
    [Column("cont_id"), Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Column("cust_id"), EitherRequired("SupplierId", Exclusive = true)]
    public int? CustomerId { get; set; }

    public virtual Customer Customer { get; set; }

    [Column("supp_id")]
    public int? SupplierId { get; set; }

    public virtual Supplier Supplier { get; set; }

    [Column("cont_title"), Required(AllowEmptyStrings = true), StringLength(5)]
    public string Title { get; set; }

    [Column("cont_firstname"), Required(AllowEmptyStrings = true), StringLength(50)]
    public string FirstName { get; set; }

    [Column("cont_lastname"), Display(Name = "Last Name"), Required(AllowEmptyStrings = true), StringLength(50)]
    public string LastName { get; set; }

    [Column("cont_phone"), DataType(DataType.PhoneNumber), StringLength(20)]
    public string PhoneNumber { get; set; }
}

我的 Controller :

public abstract class RepositoryController<TEntity, TKey> : EntitySetController<TEntity, TKey>
    where TEntity : BaseEntity
{
    protected readonly IRepository<TEntity> repository;
    protected readonly Func<TEntity, TKey> keySelector;

    public RepositoryController(IRepository<TEntity> repository, Func<TEntity, TKey> keySelector)
        : base()
    {
        this.repository = repository;
        this.keySelector = keySelector;
    }

    // GET api/entity
    [HttpGet]
    [Queryable]
    public override IQueryable<TEntity> Get()
    {
        return repository.Get();
    }

    public override void Delete(TKey key)
    {
        repository.Delete(GetEntityByKey(key));
        UnitOfWork.Save();
    }

    protected override TEntity GetEntityByKey(TKey key)
    {
        return repository.Get(key);
    }

    protected override TKey GetKey(TEntity entity)
    {
        return keySelector(entity);
    }

    protected override TEntity CreateEntity(TEntity entity)
    {
        if (!ModelState.IsValid)
        {
            throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
        }

        var result = repository.Insert(entity);
        UnitOfWork.Save();
        return result;
    }

    protected override TEntity UpdateEntity(TKey key, TEntity update)
    {
        if (!ModelState.IsValid)
        {
            throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
        }

        repository.Update(update, key);
        UnitOfWork.Save();
        return update;
    }
}

我的请求:http://localhost:60642/odata/Contact?$inlinecount=allpages&$top=20&$expand=Customer,Supplier

结果:

{
  "odata.error":{
    "code":"","message":{
      "lang":"en-US","value":"The query specified in the URI is not valid."
    },"innererror":{
      "message":"Could not find a property named 'Customer' on type 'System.Web.Http.OData.Query.Expressions.SelectAllAndExpand_1OfContact'.","type":"Microsoft.Data.OData.ODataException","stacktrace":"   at Microsoft.Data.OData.Query.SyntacticAst.ExpandBinder.GenerateExpandItem(ExpandTermToken tokenIn)\r\n   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()\r\n   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()\r\n   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)\r\n   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)\r\n   at Microsoft.Data.OData.Query.SyntacticAst.ExpandBinder.Bind(ExpandToken tokenIn)\r\n   at Microsoft.Data.OData.Query.SelectExpandSemanticBinder.Parse(IEdmEntityType elementType, IEdmEntitySet entitySet, ExpandToken expandToken, SelectToken selectToken, ODataUriParserConfiguration configuration)\r\n   at Microsoft.Data.OData.Query.ODataUriParser.ParseSelectAndExpandImplementation(String select, String expand, IEdmEntityType elementType, IEdmEntitySet entitySet)\r\n   at Microsoft.Data.OData.Query.ODataUriParser.ParseSelectAndExpand(String select, String expand, IEdmEntityType elementType, IEdmEntitySet entitySet)\r\n   at System.Web.Http.OData.Query.SelectExpandQueryOption.get_SelectExpandClause()\r\n   at System.Web.Http.OData.Query.Validators.SelectExpandQueryValidator.Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings)\r\n   at System.Web.Http.OData.Query.SelectExpandQueryOption.Validate(ODataValidationSettings validationSettings)\r\n   at System.Web.Http.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n   at System.Web.Http.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n   at System.Web.Http.QueryableAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)\r\n   at System.Web.Http.QueryableAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n   at System.Web.Http.QueryableAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
    }
  }
}

但我在 $metadata 上看到了它:

<EntityType Name="Contact">
    <Key>
        <PropertyRef Name="Id"/>
    </Key>
    <Property Name="Id" Type="Edm.Int32" Nullable="false"/>
    <Property Name="CustomerId" Type="Edm.Int32"/>
    <Property Name="SupplierId" Type="Edm.Int32"/>
    <Property Name="Title" Type="Edm.String" Nullable="false"/>
    <Property Name="FirstName" Type="Edm.String" Nullable="false"/>
    <Property Name="LastName" Type="Edm.String" Nullable="false"/>
    <Property Name="PhoneNumber" Type="Edm.String"/>
    <NavigationProperty Name="Customer" Relationship="Vantage.Data.Core.Entities.Vantage_Data_Core_Entities_Contact_Customer_Vantage_Data_Core_Entities_Customer_CustomerPartner" ToRole="Customer" FromRole="CustomerPartner"/>
    <NavigationProperty Name="Supplier" Relationship="Vantage.Data.Core.Entities.Vantage_Data_Core_Entities_Contact_Supplier_Vantage_Data_Core_Entities_Supplier_SupplierPartner" ToRole="Supplier" FromRole="SupplierPartner"/>
</EntityType>

我得到了类似的选择异常。怎么了?

编辑:更新。如果我尝试在扩展的同时过滤根实体上的某些内容,则会出现不同的错误。看来实体真的被搞砸了。

http://localhost:60642/odata/Contact?$top=20&$inlinecount=allpages&$filter=substringof('ORDERS',%20LastName)%20eq%20true&$expand=Customer,Supplier

{
  "odata.error":{
    "code":"","message":{
      "lang":"en-US","value":"The query specified in the URI is not valid. Could not find a property named 'LastName' on type 'System.Web.Http.OData.Query.Expressions.SelectAllAndExpand_1OfContact'."
    },"innererror":{
      "message":"Could not find a property named 'LastName' on type 'System.Web.Http.OData.Query.Expressions.SelectAllAndExpand_1OfContact'.","type":"Microsoft.Data.OData.ODataException","stacktrace":"   at Microsoft.Data.OData.Query.EndPathBinder.GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode)\r\n   at Microsoft.Data.OData.Query.EndPathBinder.BindEndPath(EndPathToken endPathToken, BindingState state)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.BindEndPath(EndPathToken endPathToken)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.Bind(QueryToken token)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.BindFunctionParameter(FunctionParameterToken token)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.Bind(QueryToken token)\r\n   at Microsoft.Data.OData.Query.FunctionCallBinder.<BindFunctionCall>b__6(FunctionParameterToken ar)\r\n   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()\r\n   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)\r\n   at Microsoft.Data.OData.Query.FunctionCallBinder.BindFunctionCall(FunctionCallToken functionCallToken, BindingState state)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.BindFunctionCall(FunctionCallToken functionCallToken)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.Bind(QueryToken token)\r\n   at Microsoft.Data.OData.Query.BinaryOperatorBinder.GetOperandFromToken(BinaryOperatorKind operatorKind, QueryToken queryToken)\r\n   at Microsoft.Data.OData.Query.BinaryOperatorBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)\r\n   at Microsoft.Data.OData.Query.MetadataBinder.Bind(QueryToken token)\r\n   at Microsoft.Data.OData.Query.FilterBinder.BindFilter(QueryToken filter)\r\n   at Microsoft.Data.OData.Query.ODataUriParser.ParseFilterImplementation(String filter, IEdmType elementType, IEdmEntitySet entitySet)\r\n   at System.Web.Http.OData.Query.FilterQueryOption.get_FilterClause()\r\n   at System.Web.Http.OData.Query.Validators.FilterQueryValidator.Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings)\r\n   at System.Web.Http.OData.Query.FilterQueryOption.Validate(ODataValidationSettings validationSettings)\r\n   at System.Web.Http.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n   at System.Web.Http.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n   at System.Web.Http.QueryableAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)\r\n   at System.Web.Http.QueryableAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n   at System.Web.Http.QueryableAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
    }
  }
}

最佳答案

我在 OData V4 中遇到了类似的问题。在这种情况下,如果你在 Get 方法上使用了一个属性并在你的配置中注册了另一个属性,它会出错,因为你调用了两次 EnableQuery 代码:

[EnableQuery]
public IQueryable<RegionEntity> Get()
{
    var result = _regionService.GetAll();
    return result;
}

在配置中

config.AddODataQueryFilter(new SecureAccessAttribute());

由于 SecureAccessAttribute 扩展了 EnableQueryAttribute,第一次调用 Validate 工作正常,第二次调用找不到该属性,因此虽然它似乎没有记录,但确保不要为一个查询调用两次!

关于c# - EntitySetController $expand 和 $select 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20423505/

相关文章:

c# - 使用 Task 时,如果 ThreadPool 已满/忙会发生什么情况?

c# - 如何使用 OpenFileDialog 类使其默认在网络区域打开?

带有由客户端分隔的 Multi-Tenancy 数据库的 Rest API

asp.net - WCF 数据服务作为库

c# - C# 中的屏幕层次结构

c# - 分配 Mahapps.Metro :IconPacks to button in code behind

c# - Autofac 结合 RegisterApiControllers 在 ApiController 上注入(inject)属性

json - Json响应使用asp.net核心在Web API中被截断

c# - OData 抛出 URI 中指定的查询无效

c# - 启动时出现 OData v4 错误 : Resource not found for the segment 'Whatever'