C# 实体框架核心中父表上相同主键的多个1到0..1关系

C# 实体框架核心中父表上相同主键的多个1到0..1关系,c#,entity-framework-core,C#,Entity Framework Core,假设我有以下对象 武器 剑 来复枪 鞠躬 我想要以下结构 武器只能是其中的一种,但必须至少是一种 所有武器必须存放在同一地点 所有武器类型都必须存储在各自相应的表中,如剑、步枪、弓。(不重复数据) 这就是我所做的 我创建了一个名为IWeapon的界面,看起来像这样 public interface IWeapon { public int Id { get; set; } [Key, ForeignKey("Weapon")] public

假设我有以下对象

  • 武器
  • 来复枪
  • 鞠躬
我想要以下结构

  • 武器只能是其中的一种,但必须至少是一种
  • 所有武器必须存放在同一地点
  • 所有武器类型都必须存储在各自相应的表中,如剑、步枪、弓。(不重复数据)
这就是我所做的
我创建了一个名为
IWeapon
的界面,看起来像这样

public interface IWeapon
{
    public int Id { get; set; }

    [Key, ForeignKey("Weapon")]
    public int WeaponId { get; set; }

    
    public Weapon Weapon{ get; set; }
}
这是我的其他课程

public class Weapon
{
    public int Id { get; set; }
    public decimal Damage { get; set; }

    public IWeapon ActualWeapon { get; set; }
}

public class Sword : IWeapon
{
    public int Id { get; set; }

    [Key, ForeignKey("Weapon")]
    public int WeaponId { get; set; }

    public Weapon Weapon{ get; set; }

    //other properties and methods
}

//same for Rifle and Bow
在定义了我的结构之后,我试图让它在实体框架核心中工作。
我在dbcontext中执行了以下操作,以建立1对1的关系

public DbSet<Weapon> Weapons { get; set; }

public DbSet<Sword> Swords { get; set; }

public DbSet<Rifle> Rifles { get; set; }

public DbSet<Bow> Bows { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Weapon>()
      .HasOne(w => (Sword)w.ActualWeapon)
      .WithOne()
      .HasForeignKey<Sword>(WeaponT => WeaponT.WeaponId);

    modelBuilder.Entity<Weapon>()
      .HasOne(w => (Rifle)w.ActualWeapon)
      .WithOne()
      .HasForeignKey<Rifle>(WeaponT => WeaponT.WeaponId);

    modelBuilder.Entity<Weapon>()
      .HasOne(w => (Bow)w.ActualWeapon)
      .WithOne()
      .HasForeignKey<Bow>(WeaponT => WeaponT.WeaponId);
}
公共数据库集{get;set;}
公共DbSet剑{get;set;}
公共DbSet步枪{get;set;}
公共DbSet Bows{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity()
.HasOne(w=>(剑)w.实际武器)
.WithOne()
.HasForeignKey(WeaponT=>WeaponT.weapontid);
modelBuilder.Entity()
.HasOne(w=>(步枪)w.实际武器)
.WithOne()
.HasForeignKey(WeaponT=>WeaponT.weapontid);
modelBuilder.Entity()
.HasOne(w=>(船首)w.实际武器)
.WithOne()
.HasForeignKey(WeaponT=>WeaponT.weapontid);
}
我面临的问题是,只有最后建立的关系才有效。因此,在这种情况下,弓将起作用,假设它是,因为所有的关系都将指向同一列,那么它不知道要使用哪一个,并以我使用modelbuilder所做的铸造为基础

是否有一种方法可以设置多个1到0..1关系到同一列,同时仍保持此结构的大部分

运行scaffoldbcontext命令

DbContext.cs 拿武器

你的桌子看起来很奇怪。为什么不是只有一个表“武器”,而这个表有一列叫做“武器类型”(弓、剑等)?如果想要拥有不同类型的剑,请创建另一个带有“ID”、“武器ID”、“名称”(龙剑、蛇剑……)和“伤害”的新表“武器类型”。目前EF核心不支持(无法映射)此类模型。您必须重新审视您的设计,或者用抽象类替换接口,(1)删除单独的表要求,并使用现有的TPH映射,或者(2)等待EF Core 5.0和TPT映射。遗憾的是,该设计非常锁定,因为它与其他系统互连。这是我在不泄露IP的情况下可以解释的最简单的方法,但保留了完整的结构以给出一个可解决的问题。每种武器类型都由我所在的公司管理situation@IvanStoev您知道TPT映射何时完成吗。我读了TPT,也认为它可以解决我的问题。核心5.0是。TPT已在中可用。TWeapon表名应为TWeaponType。TWeaponType表名应为TWeapon。更合适。二十岁(剑、弓、步枪)。TWeapon(龙剑,蛇剑…)这是一个非常适合书本类型的解决方案,几乎适用于任何其他场景。。很遗憾,我不能走这条路。我会给你竖起大拇指的
public virtual DbSet<TWeapon> TWeapon { get; set; }
public virtual DbSet<TWeaponType> TWeaponType { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<TWeapon>(entity =>
    {
        entity.ToTable("T_Weapon");

        entity.Property(e => e.Id).HasColumnName("ID");

        entity.Property(e => e.Name).HasMaxLength(100);
    });

    modelBuilder.Entity<TWeaponType>(entity =>
    {
        entity.ToTable("T_WeaponType");

        entity.Property(e => e.Id).HasColumnName("ID");

        entity.Property(e => e.Damage).HasColumnType("decimal(18, 2)");

        entity.Property(e => e.Name).HasMaxLength(100);

        entity.Property(e => e.WeaponId).HasColumnName("WeaponID");

        entity.HasOne(d => d.Weapon)
            .WithMany(p => p.TWeaponType)
            .HasForeignKey(d => d.WeaponId)
            .HasConstraintName("FK_T_WeaponType_T_Weapon");
    });

    OnModelCreatingPartial(modelBuilder);
}
public partial class TWeapon
    {
        public TWeapon()
        {
            TWeaponType = new HashSet<TWeaponType>();
        }

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

        public virtual ICollection<TWeaponType> TWeaponType { get; set; }
    }
public partial class TWeaponType
    {
        public int Id { get; set; }
        public int? WeaponId { get; set; }
        public string Name { get; set; }
        public decimal? Damage { get; set; }

        public virtual TWeapon Weapon { get; set; }
    }
var weapons = db.TWeapon.Include(x => x.TWeaponType).ToList();