c# - Ef core Odata 多对多
问题描述
我正在使用 ODATA 开发 Asp .Net Core 2.2 应用程序。我有测试应用程序来重现该问题:我无法通过 ODATA 请求请求带有链接表的链接实体。
请求:/odata/Books?$expand=BookCategories
响应错误:
"Message": "The query specified in the URI is not valid. Property 'BookCategories' on type 'GameStorageView.Data.Book' is not a navigation property or complex property. Only navigation properties can be expanded.",
"ExceptionMessage": "Property 'BookCategories' on type 'GameStorageView.Data.Book' is not a navigation property or complex property. Only navigation properties can be expanded.",
"ExceptionType": "Microsoft.OData.ODataException",
模型:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class BookCategory
{
public int BookId { get; set; }
public Book Book { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
模型创建:
modelBuilder.Entity<BookCategory>()
.HasKey(bc => new {bc.BookId, bc.CategoryId});
modelBuilder.Entity<BookCategory>()
.HasOne(bc => bc.Book)
.WithMany(b => b.BookCategories)
.HasForeignKey(bc => bc.BookId);
modelBuilder.Entity<BookCategory>()
.HasOne(bc => bc.Category)
.WithMany(c => c.BookCategories)
.HasForeignKey(bc => bc.CategoryId);
如何让它发挥作用?如何通过 odata 请求多对多实体?
升级版:
ODATA 配置:
.EntityType.Count().Filter().OrderBy().Expand(SelectExpandType.Allowed,10).Select().Page().Count();
linq 查询工作正常:
context.Book.Include(c=>c.BookCategories).ToArray()
解决方案
好的,我的解决方案不是最好的,但它有效:我们需要为其添加字段ID和唯一约束:
public class BookCategory
{
public int Id { get; set; }
public int BookId { get; set; }
public Book Book { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
和
modelBuilder.Entity<BookCategory>().HasAlternateKey(bc => bc.Id);
然后如果我们想通过 odata 加载链接实体,我们还需要将链接实体添加到 odata 路由。我使用扩展方法,所以它看起来像这样:
public static void RegisterOdataRoute<TEntity>(this ODataConventionModelBuilder builder, string name = null, bool pluralize = true) where TEntity : class
{
name = name ?? $"{typeof(TEntity).Name}";
var names = pluralize ? $"{name}s" : name;
OdataRoutes.Add(name, $"~/odata/{names}");
builder.EntitySet<TEntity>(names).EntityType.Count().Filter().OrderBy().Expand(SelectExpandType.Allowed,10).Select().Page().Count();
}
}
和
app.UseOData(builder =>
{
builder.RegisterOdataRoute<BookCategory>();
...
如果有人找到更好的解决方案,请告诉我!
推荐阅读
- r - 在 R 中创建具有条件的随机字符串向量
- python - 无法在 Jupyter Notebook 中导入 scipy
- linux - 用于在本地网络中运行 php 脚本的 bash 代码
- node.js - 使用 socket.ui 向特定房间发送消息不会做任何事情
- spring-boot - WebSecurityConfigurerAdapter 实现在库中不起作用
- java - 为什么我的 ProcessBuilder inputStream 产生的数据与来自 linux 命令行的数据不同
- bash - 如何编写一个函数来处理与正则表达式匹配的任何命令?
- javascript - 生成 N 种颜色的调色板 - 尽可能独特且相距较远,以便在图表中使用
- python - 每次调用python脚本时如何避免重新加载ML模型?
- firebase - 在 UI Firebase Auth Flutter 中显示异常错误