【问题标题】:How to configure strongly-typed entity Ids (value objects) with OData EDM如何使用 OData EDM 配置强类型实体 ID(值对象)
【发布时间】:2020-07-22 23:35:10
【问题描述】:

我是 OData 和 EDM 的新手。我正在尝试在具有 Blazor WebAssembly 项目和 .NET Core 3.1 Web API 的 Visual Studio 2019 解决方案中实现它们。我遇到的问题出在 Web API 项目中。

要使用 EDM 配置 OData,我正在调用:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
//etc.
app.UseEndpoints(endpoints =>
            {
//etc.
                endpoints.Select().Filter().OrderBy().Count().MaxTop(1000);
                endpoints.MapODataRoute("api", "api", GetEdmModel());
// etc.
            });
        }
}

GetEdmModel() 函数是:

private IEdmModel GetEdmModel()
        {
            var odataBuilder = new ODataConventionModelBuilder();
            odataBuilder.EntitySet<ViewStudentDto>("Students");

            return odataBuilder.GetEdmModel();
        }

在运行时出现错误:

System.InvalidOperationException:实体集 Students 基于类型 > MySchool.Dtos.Students.ViewStudentDto 没有定义键

我理解错误。它抱怨我的 DTO 类 ViewStudentDto 没有定义唯一标识符属性。但它有。它是公开的,并且该属性按照惯例命名为Id。问题是该属性的类型不是 OData 规范中的 Edm 原始类型之一:

  • Edm.Boolean
  • Edm.Byte
  • Edm.Date
  • Edm.DateTimeOffset
  • Edm.Decimal
  • Edm.持续时间
  • Edm.Guid
  • Edm.Int16
  • Edm.Int32
  • Edm.Int64
  • Edm.SByte
  • Edm.String
  • Edm.TimeOfDay

我的 Id 属性是一个名为 StudentId 的强类型 Id(值对象),其基础类型为 System.Guid,映射到 Edm.Guid

通过使用 TypeConverters、JsonConverters 和 EF 配置,可以将强类型 ID 与 Entity Framework Core 和 Json 序列化一起使用。肯定可以通过某种类型转换将强类型 ID 与 EDM/OData 一起使用吗?

谁能指导我如何配置 EDM/OData 以识别我的 StudentId 值对象可以解压缩为简单的 Edm.Guid 以便它不会引发此异常?

如果以上内容不足以看出我遇到的问题,这里有一个最小的复制:

https://github.com/BenjaminCharlton/ODataWithStronglyTypedIdsRepro

感谢您的建议!

本杰明

【问题讨论】:

  • 您能发布您的ViewStudentDtoStudentId 课程吗?
  • 感谢您一直以来的支持!我没有在原始帖子中提供,因为我不想向您倾倒大量不必要的代码。但是,是的,当然!如果它可以帮助你帮助我,我会很乐意分享它。我用最少量的代码创建了这个 Git 存储库来显示问题。它位于:github.com/BenjaminCharlton/ODataWithStronglyTypedIdsRepro

标签: c# asp.net-core odata blazor


【解决方案1】:

使用构建器指定键:

private IEdmModel GetEdmModel()
{
    var odataBuilder = new ODataConventionModelBuilder();
    var entitySet = odataBuilder.EntitySet<ViewStudentDto>("Students");

    entitySet.EntityType.HasKey(e => e.Id);
    entitySet.EntityType.Ignore(e => e.StudentId);

    return odataBuilder.GetEdmModel();
}

并添加更新 DTO 以使用 Id 属性:

public class ViewStudentDto
{
    public Guid Id { get => StudentId.Value; set => StudentId = new StudentId(value); }

    [JsonIgnore]
    public StudentId StudentId { get; set; }

    public DateTime WhenEnrolled { get; set; }

    public string Name { get; set; }
}

【讨论】:

  • 感谢您的建议,但这并不能帮助 Edm 将我的 StudentId 对象转换为 Guid。你的想法激励我尝试一些非常相似的东西。我试过这个:entitySet.EntityType.HasKey&lt;Guid&gt;(s =&gt; s.Id.Value); 其中s 是ViewStudentDto,s.Id 是强类型StudentId 对象,s.Id.Value 是StudentId 下的System.Guid 属性。它编译但它不运行。它失败并显示System.InvalidOperationException“MemberExpressions 必须绑定到 LambdaExpression 参数。”
  • devblogs.microsoft.com/odata/…”中的方法能帮到你吗?
  • @benjamin 我用工作代码更新了我对你的仓库进行 PR 的答案
  • 我很感谢你们,@SamXu 和 @agua-from-mars 的意见!通过解决这个问题,我当然学到了很多关于 oData 配置的知识!所以@agua-from-mars,我接受了你的拉取请求并感兴趣地研究了它。毫无疑问,它现在可以构建并运行,谢谢,但它被配置为忽略强类型 ID(这是设计使然)并使用额外的原始类型 Id。我们是否必须向模型添加另一个属性,因为 oData 无法配置为使用强类型属性?
  • 也感谢@SamXu 提供指向您文章的链接。我从阅读中学到了很多。不过,这并没有让我大吃一惊,如何将 oData 配置为使用强类型 ID 作为其键。在 EntityFramework 中,在您的 IEntityTypeConfiguration 实例中,您将调用 builder.Property(s =&gt; s.Id).HasConversion(id =&gt; id.Value, v =&gt; new StudentId(v)); 来配置 EF 以在原始类型和强类型 Id 之间进行转换。所以我在 oData 的 NavigationSourceConfiguration 对象上寻找类似命名的方法或扩展方法,但没有找到。请问你知道吗?
猜你喜欢
  • 2020-10-06
  • 1970-01-01
  • 2021-11-15
  • 2014-07-31
  • 1970-01-01
  • 2015-06-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
相关资源
最近更新 更多