【问题标题】:EF Core Table Per Hierarchy - Is it possible to keep track of collections for specific Entity?EF Core Table Per Hierarchy - 是否可以跟踪特定实体的集合?
【发布时间】:2020-07-25 11:30:26
【问题描述】:

假设我将为一个类实现一个 Table Per Hierarchy,我将在其中存储这种类型的子类,这些子类由一个鉴别器(约 5 种类型)区分。 一些子类将有自己的 ICollections 和一些不会,所以这不会在超类中指定。我目前只能获取直接存储在表中的数据,但无法获取该子类的集合(集合长度将为 0) 当我从数据库中获取这个特定的子类(具有特定的鉴别器)对象时,我有什么想法可以填写这个列表吗?

【问题讨论】:

标签: c# entity-framework-core table-per-hierarchy


【解决方案1】:

这是一个完整的示例控制台项目,演示了这种方法:

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace IssueConsoleTemplate
{
    public class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
    }

    public class IceCreamAsDrink : IceCream
    {
        public string DrinkName { get; set; }
    }

    public class IceCreamWithToppings : IceCream
    {
        public ICollection<Topping> Toppings { get; set; } = new HashSet<Topping>();
    }

    public class Topping
    {
        public int ToppingId { get; set; }
        public string Name { get; set; }
        public int IceCreamWithToppingsIceCreamId { get; set; } // <-- use this exact
                                                                //     name or use the
                                                                //     Fluent API

        public IceCreamWithToppings IceCreamWithToppings { get; set; }
    }

    public class Context : DbContext
    {
        public DbSet<IceCream> IceCreams { get; set; }
        public DbSet<IceCreamAsDrink> IceCreamsAsDrink { get; set; }
        public DbSet<IceCreamWithToppings> IceCreamsWithToppings { get; set; }
        public DbSet<Topping> Toppings { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseSqlServer(
                    @"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63087805")
                .UseLoggerFactory(
                    LoggerFactory.Create(
                        b => b
                            .AddConsole()
                            .AddFilter(level => level >= LogLevel.Information)))
                .EnableSensitiveDataLogging()
                .EnableDetailedErrors();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<IceCreamWithToppings>()
                .HasMany(e => e.Toppings)
                .WithOne(e => e.IceCreamWithToppings)
                .HasForeignKey(e => e.IceCreamWithToppingsIceCreamId);

            modelBuilder.Entity<IceCream>().HasData(
                new IceCream
                {
                    IceCreamId = 1,
                    Name = "Basic Vanilla"
                });

            modelBuilder.Entity<IceCreamAsDrink>().HasData(
                new IceCreamAsDrink
                {
                    IceCreamId = 2,
                    Name = "Vanilla Ice Coffee",
                    DrinkName = "Coffee"
                });

            modelBuilder.Entity<IceCreamWithToppings>().HasData(
                new IceCreamWithToppings
                {
                    IceCreamId = 3,
                    Name = "Vanilla With Sprinkles"
                });

            modelBuilder.Entity<Topping>().HasData(
                new Topping
                {
                    ToppingId = 1,
                    Name = "Chocolate Sprinkles",
                    IceCreamWithToppingsIceCreamId = 3
                },
                new Topping
                {
                    ToppingId = 2,
                    Name = "Whipped Cream",
                    IceCreamWithToppingsIceCreamId = 3
                });
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            using var context = new Context();

            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var allIceCreams = context.IceCreams
                .OrderBy(i => i.IceCreamId)
                .ToList();

            var iceCreamsAsDrink = context.IceCreamsAsDrink
                .ToList(); 

            var iceCreamsWithToppings = context.IceCreamsWithToppings
                .Include(i => i.Toppings)
                .ToList();

            Debug.Assert(allIceCreams.Count == 3);
            Debug.Assert(iceCreamsAsDrink.Count == 1);
            Debug.Assert(iceCreamsWithToppings.Count == 1);
            Debug.Assert(iceCreamsWithToppings[0].Toppings.Count == 2);
        }
    }
}

如果您想对ToppingIceCreamWithToppings 之间的外键使用约定,则需要将外键命名为&lt;DerivedType&gt;&lt;PrimaryKeyOnBaseType&gt;,因此在这种情况下为IceCreamWithToppingsIceCreamId

或者,只需使用 Fluent API 定义关系:

public class Topping
{
    public int ToppingId { get; set; }
    public string Name { get; set; }
    public int MyForeignKeyToIceCream { get; set; } // <-- non-convention name
    
    public IceCreamWithToppings IceCreamWithToppings { get; set; }
}

public class Context : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<IceCreamWithToppings>()
            .HasMany(e => e.Toppings)
            .WithOne(e => e.IceCreamWithToppings)
            .HasForeignKey(e => e.MyForeignKeyToIceCream);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多