EF Core 6/OData管理无键表/实体及GetEdmModel报错解决方案
OData配置无键数据表抛出EDM验证错误的解决方法
问题场景
需要将无键数据类型存储到数据表中,并通过API控制器进行管理,调用GetEdmModel方法时抛出OData验证错误,错误截图如下:
初始实现代码
实体类定义:
[Keyless] public class UserDocuments { [StringLength(30)] public string UserID { get; set; } = string.Empty; public Guid DocumentID { get; set; } = Guid.Empty; public int Version { get; set; } = -1; }
EDM模型构建逻辑:
public static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<UserDocuments>("UserDocuments"); return builder.GetEdmModel(); }
尝试过的Fluent API配置(未生效):
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<UserDocuments>() .HasNoKey() .ToTable("UserDocuments"); base.OnModelCreating(modelBuilder); }
EF Core中
[Keyless]特性与HasNoKey()Fluent配置效果完全等效,但两种方式都无法通过OData的模型验证。
错误原因
OData的EntitySet<T>注册方法仅支持带主键的实体类型,无键类型不符合OData实体集的主键约束要求,直接注册必然抛出验证错误。
可行解决方案
方案1(推荐):配置组合主键替代无键配置
UserDocuments实体中UserID+DocumentID+Version三个字段本身可以唯一标识表中的单行记录,完全不需要配置为无键类型,直接配置组合主键即可同时满足EF Core和OData的规则:
- 移除实体类上的
[Keyless]特性,删除OnModelCreating中的HasNoKey()配置 - 添加组合主键配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<UserDocuments>() .HasKey(ud => new { ud.UserID, ud.DocumentID, ud.Version }) .ToTable("UserDocuments"); base.OnModelCreating(modelBuilder); } - 原有
GetEdmModel中的EntitySet<UserDocuments>配置无需修改,启动后不会再抛出验证错误,可正常通过OData控制器管理该表数据。
方案2:保留无键配置,通过OData函数返回集合
如果必须保留EF Core层面的无键配置(例如实体映射的是只读数据库视图),则不能将其注册为实体集,需要注册为复杂类型,通过自定义OData函数返回结果:
- 调整EDM模型配置:
public static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); // 将无键类型注册为复杂类型 builder.ComplexType<UserDocuments>(); // 配置返回该类型集合的OData函数 var getDocsFunc = builder.Function("ListUserDocuments"); getDocsFunc.ReturnsCollection<UserDocuments>(); return builder.GetEdmModel(); } - 在控制器中实现对应函数的端点,返回无键实体的查询结果即可。注意该方式不会生成OData默认的实体集路由,仅能通过配置的函数端点访问数据。
内容的提问来源于stack exchange,提问作者Razzupaltuff
相关产品推荐
相关产品推荐

