Ef core Odata Many-to-many

.net asp.net c# entity-framework-core odata

Question

I'm developing Asp .Net Core 2.2 application with ODATA. I have test application to reproduce the problem: I can't request linked entities with link table via ODATA request.

Request: /odata/Books?$expand=BookCategories

response error:

"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",

model:

 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; }
    }

Model creating:

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);

How to make it work? How to request many-to-many entities via odata?

UPD:

ODATA configured: .EntityType.Count().Filter().OrderBy().Expand(SelectExpandType.Allowed,10).Select().Page().Count();

linq query works fine: context.Book.Include(c=>c.BookCategories).ToArray()

1
0
4/2/2020 4:37:02 PM

Popular Answer

Ok, my solution is not best, but it works: we need to add field Id and unique constraint to it:

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; }
    }

and

modelBuilder.Entity<BookCategory>().HasAlternateKey(bc => bc.Id);

and then if we want to load linked entities via odata, we also need to add link entity to odata routes. I use extension method so it looks like this:

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();
        }
    }

and

app.UseOData(builder =>
            {
                builder.RegisterOdataRoute<BookCategory>();
                    ...

If someone found a better solution, please let me know!

0
4/11/2020 6:43:22 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow