如何在ASP.NET Core中使用无主键数据库表(EF Core+OData场景)
处理ASP.NET Core中无主键的数据库表(EF Core + OData场景)
我刚好碰到过类似的棘手场景,EF Core本身要求实体必须有主键才能正常生成和操作,而OData也依赖键来实现路由和查询功能,所以得从EF Core和OData两个层面配合处理:
1. 先解决EF Core的实体映射问题
因为你没有权限修改数据库,所以只能在代码层面做配置,分两种常见情况处理:
情况A:表有唯一组合列(可作为逻辑主键)
如果cmn.ReshteNerkhItem表存在一组列的组合是全局唯一的(比如ReshteId+ItemId),那可以把这组列设为复合主键,这样EF Core就能正常识别实体了:
方法1:用数据注解标注实体
手动创建对应的实体类(因为scaffold工具失败,只能自己写):
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace YourProject.Models.Entities { [Table("ReshteNerkhItem", Schema = "cmn")] public class ReshteNerkhItem { // 用[Key] + [Column(Order)]定义复合主键的顺序 [Key] [Column(Order = 1)] public int ReshteId { get; set; } [Key] [Column(Order = 2)] public int ItemId { get; set; } // 其他列根据数据库表结构逐一添加 public decimal NerkhValue { get; set; } public DateTime CreatedAt { get; set; } } }
方法2:用Fluent API配置(更灵活,推荐)
在你的SeeMiddleContext的OnModelCreating方法中添加配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 给ReshteNerkhItem配置复合主键 modelBuilder.Entity<ReshteNerkhItem>() .HasKey(r => new { r.ReshteId, r.ItemId }); // 保留scaffold生成的其他表配置 base.OnModelCreating(modelBuilder); }
情况B:表没有任何唯一列(完全无主键)
这种情况EF Core提供了HasNoKey()的特殊配置,允许你映射无主键的表,但要注意:EF Core不支持对这类实体做Update/Delete操作,只能执行查询和插入:
首先创建不带主键注解的实体类:
using System.ComponentModel.DataAnnotations.Schema; namespace YourProject.Models.Entities { [Table("ReshteNerkhItem", Schema = "cmn")] public class ReshteNerkhItem { // 所有列都不需要加[Key]注解 public int SomeColumn { get; set; } public string AnotherColumn { get; set; } public decimal NerkhValue { get; set; } } }
然后在DbContext中配置无主键映射:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<ReshteNerkhItem>() .HasNoKey(); // 明确告诉EF Core这个实体没有数据库主键 base.OnModelCreating(modelBuilder); }
2. 适配OData的键要求
OData必须为每个实体集定义键才能正常工作,所以即使你用了HasNoKey()的EF配置,也要给OData指定一个“逻辑键”(哪怕是临时选的列):
新建一个OData模型配置类:
using Microsoft.OData.ModelBuilder; public class ReshteNerkhItemODataConfig : IEdmModelConfiguration { public void Apply(ODataModelBuilder builder) { var entitySet = builder.EntitySet<ReshteNerkhItem>("ReshteNerkhItem").EntityType; // 随便选一个列作为OData的键(比如SomeColumn),只要能让OData识别实体即可 entitySet.HasKey(r => r.SomeColumn); } }
然后在Program.cs(或Startup.cs)中注册OData时加载这个配置:
builder.Services.AddControllers().AddOData(options => { options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(100); options.AddRouteComponents("odata", GetEdmModel()); }); // 定义Edm模型的辅助方法 private static IEdmModel GetEdmModel() { var builder = new ODataConventionModelBuilder(); // 应用自定义的ReshteNerkhItem配置 new ReshteNerkhItemODataConfig().Apply(builder); // 添加其他实体集的配置... return builder.GetEdmModel(); }
最后补充的注意事项
- 用复合主键的实体,EF Core和OData都能正常支持所有CRUD操作
- 用
HasNoKey()的实体,只能做查询和插入,执行Update/Delete会直接报错(因为EF无法定位要修改的行) - 如果你的OData接口需要完整支持修改操作,最好还是和DBA沟通,看能不能给表加一个自增主键列——这是最彻底的解决方案,不过你说没权限的话,就只能用前面的方法替代了
内容的提问来源于stack exchange,提问作者SalShah
相关产品推荐
相关产品推荐

