如何使用OData EDM配置强类型实体ID(值对象)



我是OData和EDM的新手。我试图在Visual Studio 2019中的解决方案中实现它们,该解决方案具有Blazor WebAssembly项目和.NET Core 3.1 web API。我遇到的问题是在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.
});
}
}

GetEdmMode((函数是:

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.Decimal
  • Edm.Duration
  • Edm.Guid
  • Edm.Int16
  • Edm.Int32
  • Edm.Int64
  • Edm.SByte
  • Edm.String
  • Edm.TimeOfDay

My Id属性是一个名为StudentId的强类型Id(值对象(,其底层类型为System.Guid,映射到Edm.Guid

通过使用TypeConverters、JsonConverters和EF配置,可以将强类型ID与实体框架核心和Json序列化一起使用。当然,使用某种类型转换将强类型Id与EDM/OData一起使用是可能的吗?

有人能指导我如何配置EDM/OData来识别我的StudentId值对象可以被解压缩为一个简单的Edm.Guid,这样它就不会抛出这个异常吗?

如果以上还不足以看出我遇到的问题,这里有一个最低限度的重新编程:

https://github.com/BenjaminCharlton/ODataWithStronglyTypedIdsRepro

谢谢你的建议!

Benjamin

使用生成器指定密钥:

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; }
}

我也一直在与强类型id和OData作斗争,发现在这种情况下,有时创建对象的属性接口会有所帮助。

在我的情况下,我创建了一个名为IdInterface的新属性

[StronglyTypedId]
[EfCoreValueConverterAttribute(typeof(EfCoreValueConverter))]
public partial struct CompanyId { }
public class Company
{
public CompanyId Id { get; set; }
[NotMapped]
public int IdInterface
{
get => Id.Value;
set { Id = new CompanyId(value); }
}
}

然后将EDM更改为引用IdInterface作为密钥,删除Id,并将IdInterface重命名为Id

var a = builder.EntitySet<Company>(nameof(CompaniesController).Replace("Controller", ""));
a.EntityType.HasKey(x => x.IdInterface);
a.EntityType.Ignore(x => x.Id);
a.EntityType.Property(x => x.IdInterface).Name = "Id";

相关内容

  • 没有找到相关文章

最新更新