我是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";