我正在尝试使用OData
提供的EntitySetController
来获取表格的结果页面。但是,我对$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; }
}
我的控制器:
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)"
}
}
}
答案 0 :(得分:2)
如果您想使用自己的属性,则需要注册它!
只需致电config.EnableQuerySupport(new ControlledQueryableAttribute());
答案 1 :(得分:1)
NavigationProperties与Properties不同,我建议首先通过创建常规的“Customer”属性来检查它。
答案 2 :(得分:1)
我找到了。正在慢慢删除我的解决方案的部分,直到它工作。
我的速记可查询属性破坏了它:
public sealed class ControlledQueryableAttribute : QueryableAttribute
{
public ControlledQueryableAttribute()
{
this.AllowedArithmeticOperators = AllowedArithmeticOperators.None;
this.AllowedFunctions = AllowedFunctions.AllFunctions;
this.AllowedLogicalOperators = AllowedLogicalOperators.All;
this.AllowedQueryOptions =
AllowedQueryOptions.Skip |
AllowedQueryOptions.Top |
AllowedQueryOptions.Filter |
AllowedQueryOptions.OrderBy |
AllowedQueryOptions.InlineCount |
AllowedQueryOptions.Select |
AllowedQueryOptions.Expand;
this.MaxTop = 100;
}
}
似乎只是让这个超类掩盖了$expand
或$select
需要的东西。我还没有考虑过这么简单的事情。
确认简单的测试解决方案。
答案 3 :(得分:1)
我在OData V4中遇到了类似的问题。在这种情况下,如果您在Get方法上使用了一个属性并在配置中注册了另一个属性,则会发生错误,因为您正在调用EnableQuery代码两次:
[EnableQuery]
public IQueryable<RegionEntity> Get()
{
var result = _regionService.GetAll();
return result;
}
并在配置中
config.AddODataQueryFilter(new SecureAccessAttribute());
由于SecureAccessAttribute扩展了EnableQueryAttribute,第一次调用Validate工作正常,第二次无法找到属性,所以尽管似乎没有记录,但请确保不要为一次查询调用两次!
答案 4 :(得分:0)
对于OData V4,即使我们为控制器内的控制器或方法指定[EnableQuery],也无法使用。因此,如果您已全局启用查询,请删除所有属性。