using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace DataLayer.Configurations { internal class BookConfig : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder entity) { entity.HasKey(b => b.BookId); entity.HasIndex(b => b.AudibleProductId); entity.OwnsOne(b => b.Rating); // // CRUCIAL: ignore unmapped collections, even get-only // entity.Ignore(nameof(Book.Authors)); entity.Ignore(nameof(Book.Narrators)); //// these don't seem to matter //entity.Ignore(nameof(Book.AuthorNames)); //entity.Ignore(nameof(Book.NarratorNames)); //entity.Ignore(nameof(Book.HasPdfs)); // OwnsMany: "Can only ever appear on navigation properties of other entity types. // Are automatically loaded, and can only be tracked by a DbContext alongside their owner." entity .OwnsMany(b => b.Supplements, b_s => { b_s.WithOwner(s => s.Book) .HasForeignKey(s => s.BookId); b_s.HasKey(s => s.SupplementId); }); // even though it's owned, we need to map its backing field entity .Metadata .FindNavigation(nameof(Book.Supplements)) .SetPropertyAccessMode(PropertyAccessMode.Field); // owns it 1:1, store in separate table entity .OwnsOne(b => b.UserDefinedItem, b_udi => { b_udi.WithOwner(udi => udi.Book) .HasForeignKey(udi => udi.BookId); b_udi.Property(udi => udi.BookId).ValueGeneratedNever(); b_udi.ToTable(nameof(Book.UserDefinedItem)); // owns it 1:1, store in same table b_udi.OwnsOne(udi => udi.Rating); }); entity .Metadata .FindNavigation(nameof(Book.ContributorsLink)) // PropertyAccessMode.Field : Contributions is a get-only property, not a field, so use its backing field .SetPropertyAccessMode(PropertyAccessMode.Field); entity .Metadata .FindNavigation(nameof(Book.SeriesLink)) // PropertyAccessMode.Field : Series is a get-only property, not a field, so use its backing field .SetPropertyAccessMode(PropertyAccessMode.Field); entity .HasOne(b => b.Category) .WithMany() .HasForeignKey(b => b.CategoryId); } } }