【问题标题】:How do I correctly filter my DataSet by GUID using OData?如何使用 OData 按 GUID 正确过滤我的数据集?
【发布时间】:2017-01-11 18:40:50
【问题描述】:

如何按 GUID 正确过滤我的 DataSet

我正在公开一个 OData 端点,并尝试导航到 URL:

http://localhost:5001/mystuf/api/v2/AccountSet?$filter=AccountId%20eq%20guid%2703a0a47b-e3a2-e311-9402-00155d104c22%27

当我的 OData 端点尝试过滤该 GUID 上的 DataSet 时,我得到:

"message": "Invalid 'where' condition. An entity member is invoking
an invalid property or method.", "type": "System.NotSupportedException"
> 
{
  "odata.error": {
    "code": "",
    "message": {
      "lang": "en-US",
      "value": "An error has occurred."
    },
    "innererror": {
      "message": "Invalid 'where' condition. An entity member is invoking an invalid property or method.",
      "type": "System.NotSupportedException",
      "stacktrace": "   at Microsoft.Xrm.Sdk.Linq.QueryProvider.ThrowException(Exception exception)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.FindValidEntityExpression(Expression exp, String operation)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.TranslateWhereCondition(BinaryExpression be, FilterExpressionWrapper parentFilter, Func`2 getFilter, Boolean negate)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.TranslateWhere(String parameterName, BinaryExpression be, FilterExpressionWrapper parentFilter, Func`2 getFilter, List`1 linkLookups, Boolean negate)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.TranslateWhereBoolean(String parameterName, Expression exp, FilterExpressionWrapper parentFilter, Func`2 getFilter, List`1 linkLookups, BinaryExpression parent, Boolean negate)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.TranslateWhere(QueryExpression qe, String parameterName, Expression exp, List`1 linkLookups)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.GetQueryExpression(Expression expression, Boolean& throwIfSequenceIsEmpty, Boolean& throwIfSequenceNotSingle, Projection& projection, NavigationSource& source, List`1& linkLookups)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.Execute[TElement](Expression expression)
   at Microsoft.Xrm.Sdk.Linq.QueryProvider.GetEnumerator[TElement](Expression expression)
   at Microsoft.Xrm.Sdk.Linq.Query`1.GetEnumerator()
   at Microsoft.Xrm.Sdk.Linq.Query`1.System.Collections.IEnumerable.GetEnumerator()
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
   at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
   at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)
   at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
   --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__24.MoveNext()
   --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at System.Web.Http.Owin.HttpMessageHandlerAdapter.<BufferResponseContentAsync>d__13.MoveNext()"
    }
  }
}

CSDL 文件的开头如下所示:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <Schema Namespace="Xrm" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">

      <EntityType Name="Account">
        <Key>
          <PropertyRef Name="AccountId" />
        </Key>
        <Property Name="TerritoryCode" Type="Microsoft.Crm.Sdk.Data.Services.OptionSetValue" Nullable="false" />
        <Property Name="LastUsedInCampaign" Type="Edm.DateTime" Nullable="true" />
…

被触发的控制器是:

public IHttpActionResult Get(ODataQueryOptions<Account> options)
{
    var retval = options.ApplyTo(_accountService.GetAccountSet());

    return Ok(retval);

}

而上述Get() 方法将过滤器应用于:

public IQueryable<Account> GetAccountSet()
{
    return _xrmServiceContext.AccountSet;
}

如何按 GUID 正确过滤我的 DataSet

请注意,当我返回时:

return _xrmServiceContext.AccountSet.Take(2);

然后数据正确返回给客户端(序列化/反序列化正确工作);但是,过滤器根本没有应用。

【问题讨论】:

  • 您的 OData 查询不正确。过滤器的查询结构如下:$filter=property eq 'value',而不是 $filter=property eq property 'value'。试试 $filter=AccountId eq 'guid value'。
  • “在 URI 中指定的查询无效。检测到类型不兼容的二元运算符。找到运算符类型 'Equal' 的操作数类型 'Edm.Guid' 和 'Edm.String'。” },
  • /api/v2/AccountSet?$filter=AccountId eq '03a0a47b-e3a2-e311-9402-00155d104c22'
  • 这意味着您正在尝试将 Edm.Guid 与 Edm.String 进行比较。我假设您的 AccountSet 字段是 Edm.String,所以如果您将其更改为 Edm.Guid,它可能会起作用。
  • AFAIK,如果您删除单引号,OData 将强制转换为 GUID。

标签: c# asp.net-core odata dynamics-crm-2011


【解决方案1】:

根据updated documentation 的解决方案取决于AccountId 字段的类型。

如果AccountId 类型是Guid(很可能是您的情况),那么与guid 文字的比较应该在没有guid 关键字或将其放入引号的情况下编写。所以有效的查询应该是这样的:

AccountId eq 03a0a47b-e3a2-e311-9402-00155d104c22

结果 url 将是这样的:

http://localhost:5001/mystuf/api/v2/AccountSet?$filter=AccountId%20eq%2003a0a47b-e3a2-e311-9402-00155d104c22

但如果AccountId 类型是String 并且它包含guid 的字符串表示,则应使用字符串文字规则并将其放在单引号中,如下所示:

AccountId eq '03a0a47b-e3a2-e311-9402-00155d104c22'

结果 url 将是这样的:

http://localhost:5001/mystuf/api/v2/AccountSet?$filter=AccountId%20eq%20%2703a0a47b-e3a2-e311-9402-00155d104c22%27

您可以测试两个网址,看看哪个适合您:)

【讨论】:

  • GuidValue 是有关 guid 文字的文档中示例中的字段名称。请阅读我的答案的下一行,并以当前数据库AccountId eq 03a0a47b-e3a2-e311-9402-00155d104c22 为例。我将删除此示例以避免混淆
猜你喜欢
  • 2021-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
相关资源
最近更新 更多