“{type}”类型中不存在属性“{property}”—— 但实际上是存在的。这可能是 OData 配置问题导致的。

4
我有一个Blazor WASM应用程序,它有一个OData后端。我试图配置我的模型中的NavigationProperty,以便我可以使用$expand=查询参数返回更多数据,但是当我尝试进行PATCH请求时(GET正常工作),我一直收到以下错误: Microsoft.OData.ODataException: 属性“JobId”在类型“Coin.ODataOrderHeader”上不存在。确保仅使用类型定义的属性名称或将该类型标记为开放类型。 但实际上它是存在的!不仅仅是在模型中:
public partial class ODataOrderHeader
{
        [Key]
        public int OrderId { get; set; }

        [Column("JobID")]
        [ForeignKey("Job")]
        public int JobId { get; set; }
        ...
        [System.Text.Json.Serialization.JsonPropertyName("Job")]
        public virtual Jobs Job { get; set; }
}

但在 $metadata 文档中也是如此:

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="Coin" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            ...
            <EntityType Name="ODataOrderHeader">
                <Key>
                    <PropertyRef Name="OrderId" />
                </Key>
                <Property Name="OrderId" Type="Edm.Int32" Nullable="false" />
                <Property Name="JobId" Type="Edm.Int32" />
                ...
                <NavigationProperty Name="Job" Type="Coin.Jobs">
                    <ReferentialConstraint Property="JobId" ReferencedProperty="JobId" />
                </NavigationProperty>
            </EntityType>
            ...
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

这里是创建模型的代码:
        private IEdmModel GetEdmModel()
        {
            var builder = new ODataConventionModelBuilder();
            builder.Namespace = "Coin";
            builder.ContainerName = "CoinContainer";
            ...
            var orders = builder.EntitySet<ODataOrderHeader>("Orders");
            return builder.GetEdmModel();
        }

我应该指出,ODataOrderHeader 更像是一个数据传输对象(DTO)类型,而 Jobs 是一个 EF 脚手架生成的类型。

这是调用 API 的 Simple.OData.Client 代码:

    private async void UpdateItem()
    {
        ODataClient client = new ODataClient(new ODataClientSettings(HttpClient, new Uri("odata", UriKind.Relative)));

        await client.For<ODataOrderHeader>("Orders")
            .Key(currentOrder.OrderId)
            .Set(currentOrder)
            .UpdateEntryAsync();
    }

这里是上面代码调用的控制器动作:

        [ODataRoute("/orders({key})")]
        public async Task<IActionResult> Patch([FromODataUri] int key, Delta<ODataOrderHeader> order)
        {
            if (!ModelState.IsValid)
                return BadRequest();

            ...
        }

最后,完整的错误信息如下:

Unhandled Exception:
Microsoft.OData.ODataException: The property 'JobId' does not exist on type 'Coin.ODataOrderHeader'. Make sure to only use property names that are defined by the type or mark the type as open type.
  at Microsoft.OData.WriterValidationUtils.ValidatePropertyDefined (Microsoft.OData.PropertySerializationInfo propertyInfo, System.Boolean throwOnUndeclaredProperty) <0x61a9028 + 0x00098> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WritePropertyInfo (Microsoft.OData.ODataPropertyInfo propertyInfo, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6120d78 + 0x000f8> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperty (Microsoft.OData.ODataProperty property, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x61203e8 + 0x00018> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperties (Microsoft.OData.Edm.IEdmStructuredType owningType, System.Collections.Generic.IEnumerable`1[T] properties, System.Boolean isComplexValue, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6011c28 + 0x00048> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource (Microsoft.OData.ODataResource resource) <0x5ef5478 + 0x003d6> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass121_0.<WriteStartResourceImplementation>b__0 () <0x5ed80f0 + 0x00082> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.InterceptException (System.Action action) <0x5ed3f20 + 0x00042> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation (Microsoft.OData.ODataResource resource) <0x5ed3a78 + 0x00076> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass49_0.<WriteStartAsync>b__0 () <0x5ed3628 + 0x0000c> in <filename unknown>:0 
  at Microsoft.OData.TaskUtils.GetTaskForSynchronousOperation (System.Action synchronousOperation) <0x5ed34e0 + 0x0000a> in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---

  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryPropertiesAsync (Microsoft.OData.ODataWriter entryWriter, Microsoft.OData.ODataResource entry, System.Collections.Generic.IDictionary`2[TKey,TValue] links) <0x5ed2260 + 0x000f2> in <filename unknown>:0 
  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryContentAsync (System.String method, System.String collection, System.String commandText, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5477750 + 0x0049c> in <filename unknown>:0 
  at Simple.OData.Client.RequestWriterBase.CreateUpdateRequestAsync (System.String collection, System.String entryIdent, System.Collections.Generic.IDictionary`2[TKey,TValue] entryKey, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5814b98 + 0x0020c> in <filename unknown>:0 
  at Simple.OData.Client.RequestBuilder.UpdateRequestAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577cd28 + 0x00386> in <filename unknown>:0 
  at Simple.OData.Client.ODataClient.UpdateEntryAsync (Simple.OData.Client.FluentCommand command, System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577bcc8 + 0x00162> in <filename unknown>:0 
  at Simple.OData.Client.BoundClient`1[T].UpdateEntryAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x576d9a0 + 0x00230> in <filename unknown>:0 
  at Coin.Client.Pages.OrderEdit.UpdateItem () [0x000ac] in C:\Users\trichardson\source\Workspaces\Corsi\COIN2\Client\Pages\OrderEdit.razor:393 
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) <0x6547930 + 0x0000c> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) <0x65478e0 + 0x00022> in <filename unknown>:0 
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x3112fc8 + 0x00100> in <filename unknown>:0 
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x310b7d8 + 0x00010> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () <0x5743290 + 0x00038> in <filename unknown>:0 
  at System.Threading.ThreadPoolWorkQueue.Dispatch () <0x39a89b8 + 0x00102> in <filename unknown>:0 
  at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () <0x39a4578 + 0x00000> in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: Microsoft.OData.ODataException: The property 'JobId' does not exist on type 'Coin.ODataOrderHeader'. Make sure to only use property names that are defined by the type or mark the type as open type.
  at Microsoft.OData.WriterValidationUtils.ValidatePropertyDefined (Microsoft.OData.PropertySerializationInfo propertyInfo, System.Boolean throwOnUndeclaredProperty) <0x61a9028 + 0x00098> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WritePropertyInfo (Microsoft.OData.ODataPropertyInfo propertyInfo, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6120d78 + 0x000f8> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperty (Microsoft.OData.ODataProperty property, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x61203e8 + 0x00018> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperties (Microsoft.OData.Edm.IEdmStructuredType owningType, System.Collections.Generic.IEnumerable`1[T] properties, System.Boolean isComplexValue, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6011c28 + 0x00048> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource (Microsoft.OData.ODataResource resource) <0x5ef5478 + 0x003d6> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass121_0.<WriteStartResourceImplementation>b__0 () <0x5ed80f0 + 0x00082> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.InterceptException (System.Action action) <0x5ed3f20 + 0x00042> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation (Microsoft.OData.ODataResource resource) <0x5ed3a78 + 0x00076> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass49_0.<WriteStartAsync>b__0 () <0x5ed3628 + 0x0000c> in <filename unknown>:0 
  at Microsoft.OData.TaskUtils.GetTaskForSynchronousOperation (System.Action synchronousOperation) <0x5ed34e0 + 0x0000a> in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---

  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryPropertiesAsync (Microsoft.OData.ODataWriter entryWriter, Microsoft.OData.ODataResource entry, System.Collections.Generic.IDictionary`2[TKey,TValue] links) <0x5ed2260 + 0x000f2> in <filename unknown>:0 
  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryContentAsync (System.String method, System.String collection, System.String commandText, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5477750 + 0x0049c> in <filename unknown>:0 
  at Simple.OData.Client.RequestWriterBase.CreateUpdateRequestAsync (System.String collection, System.String entryIdent, System.Collections.Generic.IDictionary`2[TKey,TValue] entryKey, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5814b98 + 0x0020c> in <filename unknown>:0 
  at Simple.OData.Client.RequestBuilder.UpdateRequestAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577cd28 + 0x00386> in <filename unknown>:0 
  at Simple.OData.Client.ODataClient.UpdateEntryAsync (Simple.OData.Client.FluentCommand command, System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577bcc8 + 0x00162> in <filename unknown>:0 
  at Simple.OData.Client.BoundClient`1[T].UpdateEntryAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x576d9a0 + 0x00230> in <filename unknown>:0 
  at Coin.Client.Pages.OrderEdit.UpdateItem () [0x000ac] in C:\Users\trichardson\source\Workspaces\Corsi\COIN2\Client\Pages\OrderEdit.razor:393 
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) <0x6547930 + 0x0000c> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) <0x65478e0 + 0x00022> in <filename unknown>:0 
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x3112fc8 + 0x00100> in <filename unknown>:0 
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x310b7d8 + 0x00010> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () <0x5743290 + 0x00038> in <filename unknown>:0 
  at System.Threading.ThreadPoolWorkQueue.Dispatch () <0x39a89b8 + 0x00102> in <filename unknown>:0 
  at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () <0x39a4578 + 0x00000> in <filename unknown>:0 
Uncaught ExitStatusThe program '' has exited with code -1 (0xffffffff).

我是否忽略了配置错误或者控制器动作出现了问题?


它可能区分大小写吗?尝试将[Column("JobID")]更改为[Column("JobId")] - Guru Stron
@GuruStron 我希望如此。数据库中的列名为“JobID”,但是即使没有这个注释,应用程序的功能也完全相同。 - Bigg_T76
1个回答

1
对于未来遇到此问题的任何人,我能够发现更多信息。首先,在我的Jobs类上添加一些数据注释[IgnoreDataMember],并在实例化ODataClient时添加{IgnoreUnmappedProperties = true},我能够获得不同的错误。大致是这样:字典中不存在键'JobId'
为了理解背景,我正在尝试进行 OData 所称的 "深度更新"。我想在更新父实体的同时更新子实体。然而,Simple.OData.Client 不支持深度更新、深度链接或深度创建。这里有一个来自 Simple.OData.Client 的 GitHub 页面的问题,已经五年了,讨论了这个问题,不幸的是,看起来这个包的开发已经停止了 ("Simple.OData.Client 的未来""项目死了吗?")。由于它不支持 "深度更新",所以它不知道如何生成请求 URL,这就是为什么我的 PATCH 请求失败的原因。

也许还有一种方法可以从Simple.OData.Client中“强制”正确的URL和格式。欢迎任何人来证明我是错的! - Bigg_T76
非常感谢您的回答,它让我度过了这个晚上! - kavanka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接