ASP.NET Core OData 8.0 子级集合端点/Documents(1)/Lines(1)/SubLines实现问题
问题修复方案
1. 实体类修正
访问修饰符问题
Document类中的Lines属性无public修饰符,OData无法识别该导航属性,需改为public;同时确保所有导航属性均可访问。
复合主键定义
DocLines的主键应为DocEntry + LineNum(复合键),单个LineNum无法唯一标识记录;DocSubLines同理需设置复合主键(DocEntry + BaseLineId + LineNum)保证唯一性。
修正后的实体类代码:
public class Document { [Key] public int DocEntry { get; set; } public int DocNum { get; set; } // 改为public,OData才能识别导航属性 public List<DocLines> Lines { get; set; } = new List<DocLines>(); } public class DocLines { // 复合主键:DocEntry + LineNum [Key] public int DocEntry { get; set; } [Key] public int LineNum { get; set; } public string ItemCode { get; set; } public List<DocSubLines> SubLines { get; set; } = new List<DocSubLines>(); } public class DocSubLines { // 复合主键:DocEntry + BaseLineId + LineNum [Key] public int DocEntry { get; set; } [Key] public int BaseLineId { get; set; } [Key] public int LineNum { get; set; } public string Field { get; set; } }
2. EDM模型配置修正
需正确配置实体的复合主键及导航关系的可展开性:
public override void BuildGeneratedEdmModel(ODataConventionModelBuilder builder) { var testDocument = builder.EntityType<Document>(); testDocument.HasKey(c => c.DocEntry); testDocument.HasMany(p => p.Lines).IsExpandable(); var testDocumentLine = builder.EntityType<DocLines>(); // 配置DocLines的复合主键 testDocumentLine.HasKey(c => new { c.DocEntry, c.LineNum }); testDocumentLine.HasMany(p => p.SubLines).IsExpandable(); var testDocSubLines = builder.EntityType<DocSubLines>(); // 配置DocSubLines的复合主键 testDocSubLines.HasKey(c => new { c.DocEntry, c.BaseLineId, c.LineNum }); var testDocuments = builder.EntitySet<Document>("Documents"); }
3. 控制器方法修正
参数不匹配问题
GetSubLinesFromDocument仅接收一个key参数,但/Documents(1)/Lines(1)/SubLines需要两个标识:文档的DocEntry(1)和行的LineNum(1),需添加第二个参数。
方法命名与路由
遵循OData约定修改方法名,或显式添加[ODataRoute]特性指定路由模板。
修正后的控制器代码:
public class DocumentsController : ODataController { private readonly YourDbContext _context; // 注入DbContext public DocumentsController(YourDbContext context) { _context = context; } // odata/Documents working [EnableQuery] public IQueryable<Document> Get() { return _context.Documents.AsQueryable(); } // odata/Documents(1)/Lines working [EnableQuery] public IQueryable<DocLines> GetLinesFromDocument(int key) { return _context.DocLines.Where(l => l.DocEntry == key); } [EnableQuery] // 修正路由与参数:匹配/Documents({key})/Lines({lineKey})/SubLines [ODataRoute("Documents({key})/Lines({lineKey})/SubLines")] public IQueryable<DocSubLines> GetSubLinesFromDocLines(int key, int lineKey) { // 查询对应文档下指定行的子行 return _context.DocSubLines.Where(s => s.DocEntry == key && s.BaseLineId == lineKey); } }
额外验证
- 确保
DbContext中正确配置DbSet<DocLines>和DbSet<DocSubLines> - 启动项目后访问
/odata/$metadata,检查EDM模型是否正确生成导航关系和主键定义
内容的提问来源于stack exchange,提问作者Michal
相关产品推荐
相关产品推荐

