EfCore多态扩展数据

时间:2018-08-02 12:11:42

标签: c# entity-framework-core

我想要一个Root对象的集合,这些对象具有常见抽象基类的某些实现的Details属性。

这样的事情。

public class Root<TDetails>
    where TDetails : Details<TDetails>
{
    public int Id { get; set; }
    public TDetails Details { get; set; }
}

public abstract class Details<TSelf>
    where TSelf : Details<TSelf>
{
    public Root<TSelf> Root { get; set; }
}

基本上我想做类似的事情

foreach(var root in roots)
{
    // do something with root properties

    // some factory method...
    if(root.Details.GetType() == typeof(ADetails))
    {
        aDetailsHandler.Handle(root.Details);
    } else if (root.Details.GetType() == typeof(BDetails))
    {
        bDetailsHandler.Handle(root.Details);
    }
}

这是对数据建模的明智方法吗?

我想出的最好的方法是这个,但看起来真的很片状

public abstract class RootBase
{
    protected RootBase()
    {
    }

    public int Id { get;set; }
    public string Name { get;set; }

    public string DetailsType { get; protected set; }

    [NotMapped]
    public abstract DetailsBase Details { get; set; }
}

public abstract class Root<TDetails> : RootBase
    where TDetails : Details<TDetails>
{
    public Root()
    {
    }

    protected internal virtual TDetails DetailsInternal { get; set; }
    public override DetailsBase Details { get => DetailsInternal; set => DetailsInternal = (TDetails)value; }
}

public abstract DetailsBase
{
    protected DetailsBase()
    {
    }

    public int Id { get; set; }
}

public abstract Details<TSelf> : DetailsBase
    where TSelf : Details<TSelf>
{
    protected DetailsBase()
    {
    }

    public virtual Root<TSelf> Root { get; set; }
}

public class UnCoolDetails : DetailsBase
{
    public const string DetailsType = "uncool";

    public UnCoolDetails()
    {
    }

    public int UnCoolLevel { get; set; }
}

public class CoolDetails : DetailsBase
{
    public const string DetailsType = "cool";

    public CoolDetails()
    {
    }

    public string CoolName { get; set; }
}


public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    public DbSet<RootBase> Roots { get; set; }
    public DbSet<CoolDetails> CoolDetails { get; set; }
    public DbSet<UnCoolDetails> UnCoolDetails { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Configure<RootBase>(b => {
            b.ToTable("Roots");

            b.HasKey(e => e.Id);

            b.HasIndee(e => e.Name)
                .IsUnique();

            b.HasDiscriminator(e => e.DetailsType)
                .HasValue<Person<CoolDetails>>(CoolDetails.DetailsType)
                .HasValue<Person<UnCoolDetails>>(UnCoolDetails.DetailsType);
        });

        modelBuilder.Configure<CoolDetails>(b => {
            b.ToTable("CoolDetails");

            b.HasKey(e => e.Id);

            b.HasOne(e => e.Root)
                .WithOne(e => e.DetailsInternal)
                .HasForeignKey<Root<CoolDetails>>("CoolDetailsId");
        });

        modelBuilder.Configure<UnCoolDetails>(b => {
            b.ToTable("UnCoolDetails");

            b.HasKey(e => e.Id);

            b.HasOne(e => e.Root)
                .WithOne(e => e.DetailsInternal)
                .HasForeignKey<Root<UnCoolDetails>>("UnCoolDetailsId");
        });
    }
}


using(var db = new DbContext())
{
    db.Roots.Add(new Root<CoolDetails>
    {
        Name = "Config_1",
        Details = new CoolDetails
        {
            CoolName = "Super Cool"
        }
    });
    db.SaveChanges();
}

using(var db = new DbContext())
{
    var Roots = db.Roots.Include("DetailsInternal").First(x => x.Name == "Config_1");

    //Roots.First().Details.GetType() == typeof(CoolDetails);
}

0 个答案:

没有答案