【问题标题】:multiple 1 to 0..1 relationships to the same Primary Key on parent table in entity framework Core实体框架核心中父表上同一个主键的多个 1 到 0..1 关系
【发布时间】:2020-09-02 09:26:32
【问题描述】:

假设我有以下对象

  • 武器
  • 步枪

我想要以下结构。

  • 武器只能是其中之一,但必须至少是 1 个。
  • 所有武器必须存放在同一个地方。
  • 所有武器类型都必须存储在各自对应的表格中,例如剑、步枪、弓。 (不重复数据)

这就是我所做的。
我创建了一个名为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

定义我的结构后,我尝试让它在 Entity Framework Core 中工作。
我在我的 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);
}

我面临的问题是只有最后创建的关系有效。所以在这种情况下,弓会起作用,假设它是因为所有关系都进入同一列,那么它不知道要影响哪一个,并将其基于我对模型构建器所做的铸造

有没有办法为同一列设置多个 1 到 0..1 关系,同时仍保持大部分结构

【问题讨论】:

  • 你的桌子看起来很奇怪。为什么不只是 1 个表“Weapon”,而该表有名为“WeaponType”的列(弓、剑等)?如果想要拥有不同类型的剑,请创建另一个新表“WeaponType”,其中包含“ID”、“WeaponID”、“名称”(龙剑、蛇剑...)、“伤害”。
  • 目前 EF Core 不支持(无法映射)此类模型。您必须重新审视您的设计,或将接口替换为抽象类,并且 (1) 删除单独的表要求并使用现有的 TPH 映射或 (2) 等待 EF Core 5.0 和 TPT 映射
  • 遗憾的是,由于它与其他系统相互关联,因此该设计非常锁定。这是我可以在不泄露 IP 的情况下解释的最简单方法,但保留完整结构以提供可解决的问题。在我的情况下,每种武器类型都由不同的公司管理
  • @IvanStoev 你知道 TPT 映射什么时候完成吗?我在 TPT 上阅读,也认为它可以解决我的问题
  • EF Core 5.0 是 scheduled for November 2020。 TPT 已在Preview 8 中提供。

标签: c# entity-framework-core


【解决方案1】:

运行scaffold-dbcontext 命令。

DbContext.cs

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

TWeapon.cs

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

TWeaponType.cs

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

【讨论】:

  • TWeapon 表名应该是 TWeaponType。 TWeaponType 表名应该是 TWeapon。更合适。 TWeaponType(剑、弓、步枪)。 TWeapon(龙剑、蛇剑……)
  • 这是一种非常适合书本类型的解决方案,几乎可以在任何其他情况下工作。遗憾的是我不能走这条路。不过会给你一个大拇指
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多