【问题标题】:EF Core Many-To-Many Relationship Sets Both Keys to ParentEF Core 多对多关系将两个键都设置为父级
【发布时间】:2018-02-18 22:08:46
【问题描述】:

我正在构建一个模型,该模型代表可以在使用 EF Core 2.0 编写的电子商务平台中创建的典型产品。看下面的模型结构

public class GSProduct : BaseEntity
{
    [Required]
    public string Name { get; set; }

    public ICollection<GSProduct> BaseProducts { get; set; }

    public ICollection<GSRelatedProduct> ParentProducts { get; set; } 
    public ICollection<GSRelatedProduct> ChildProducts { get; set;  } 

    public ICollection<GSVendorProductInfo> VendorProductInfo { get; } = new List<GSVendorProductInfo>();

}

public class GSRelatedProduct
{

    public virtual GSProduct ParentProduct { get; set; }
    public Guid ParentProductId { get; set; }

    public virtual GSProduct ChildProduct { get; set; }
    public Guid ChildProductId { get; set; }

}

public class GSVendorProductInfo : BaseEntity
{
    public GSContact Vendor { get; set; }
    public Guid VendorId { get; set; }

    public GSProduct Product { get; set; }
    public Guid ProductId { get; set; }

    public string VendorPartNumber { get; set; }
    public int BaseUnits { get; set; }
    public double Cost { get; set; }
    public int MinOrderQty { get; set; }
    public int OrderedInMultiples { get; set; }

}

这是我为 Fluent API 设置的。

           modelBuilder.Entity<GSVendorProductInfo>()
            .HasOne(pt => pt.Product)
            .WithMany(p => p.VendorProductInfo)
            .HasForeignKey(pt => pt.ProductId);

        modelBuilder.Entity<GSVendorProductInfo>()
            .HasOne(pt => pt.Vendor)
            .WithMany(t => t.VendorProductInfo)
            .HasForeignKey(pt => pt.VendorId);

        modelBuilder.Entity<GSRelatedProduct>().HasKey(x => new { x.ParentProductId, x.ChildProductId });

        modelBuilder.Entity<GSRelatedProduct>()
            .HasOne(pt => pt.ParentProduct)
            .WithMany(t => t.ParentProducts)
            .HasForeignKey(pt => pt.ParentProductId);

        modelBuilder.Entity<GSRelatedProduct>()
            .HasOne(pt => pt.ChildProduct)
            .WithMany(t => t.ChildProducts)
            .HasForeignKey(pt => pt.ChildProductId);

还包括迁移

migrationBuilder.CreateTable(
            name: "GSRelatedProducts",
            columns: table => new
            {
                ParentProductId = table.Column<Guid>(nullable: false),
                ChildProductId = table.Column<Guid>(nullable: false),
                Optional = table.Column<bool>(nullable: false),
                Quantity = table.Column<int>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_GSRelatedProducts", x => new { x.ParentProductId, x.ChildProductId });
                table.ForeignKey(
                    name: "FK_GSRelatedProducts_GSProducts_ChildProductId",
                    column: x => x.ChildProductId,
                    principalTable: "GSProducts",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.NoAction);
                table.ForeignKey(
                    name: "FK_GSRelatedProducts_GSProducts_ParentProductId",
                    column: x => x.ParentProductId,
                    principalTable: "GSProducts",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.NoAction);
            });

脚手架/迁移工作正常,我实际上可以毫无问题地创建包含所有关系的产品。当我尝试将“RelatedProduct”添加到产品模型时出现问题。

我相应地设置了 ParentProductId 和 ChildProductId,当我创建或更新实体时,它会将 ParentProductId 和 ChildProductId 值都设置为 ParentProductId。

我已经通过调试器跟踪了代码,直到我调用 _context.Update(entity) 之前它都是正确的。之后,RelatedProduct 模型中的两个 Id 都设置为相同的值。

我不知道为什么会发生这种情况,任何建议都会很有帮助。

【问题讨论】:

  • 您的类属性到表列名的映射是如何设置的?可能是您将父 ID 设置为两列吗?你能提供一些代码吗?
  • 您指的是为表创建的迁移吗?
  • 有多个父产品有什么理由吗?
  • 这也有帮助。通常有一个映射类会说: Property(p => ParentId).HasColumnName("ParentId")
  • @Brad 父子产品联盟将是所有相关产品的列表。

标签: entity-framework asp.net-core


【解决方案1】:

我认为您的迁移生成方式存在问题。从上面的代码中,我不确定GSRelatedProduct 中子属性的用途是什么。如果您查看迁移,您会看到为父级和子级设置了相同的约束:

table.ForeignKey(
    name: "FK_GSRelatedProducts_GSProducts_ChildProductId",
    column: x => x.ChildProductId,
    principalTable: "GSProducts",
    principalColumn: "Id",
    onDelete: ReferentialAction.NoAction);
table.ForeignKey(
    name: "FK_GSRelatedProducts_GSProducts_ParentProductId",
    column: x => x.ParentProductId,
    principalTable: "GSProducts",
    principalColumn: "Id",
    onDelete: ReferentialAction.NoAction);

Parent 和 Child 具有相同的主表和主列。它们都将从GSProducts 表中获得相同的值。我无法弄清楚您的逻辑或业务流程是什么,但您实际上正在获得预期的效果。孩子应该指向别的东西吗?在您的代码中,您可能为产品和子项分配了不同的值,但这似乎被某种方式覆盖了。基本上,您的代码首先认为两者和 parent 应该具有相同的值。也就是说,Child 似乎是多余的。

您的 GSProduct 表是否是一个自引用表,您可以在其中将产品和子产品放在一起?如果是这样,那么您需要一个用于此目的的附加列,例如指向IdParentId,以便获得所需的关系。

【讨论】:

  • 目标是能够创建产品列表并将它们附加到父产品。这些项目都是 GSProduct 模型。所以对我来说,表格模型似乎是正确的。 ChidProductId 和 ParentProductId 都将引用 GSProducts 中的 ID 列,因为它们都引用 GSProduct 模型。
  • 但是你会得到实际的结果。我的理解是您的子产品 ID 应该引用 GSProduct 中的某种子类别。
  • 尝试使用INSERT INTO SQL 语句手动将一些值插入GSRelatedProduct,看看是否可行。
  • 如果我手动运行 INSERT INTO GSRelatedProducts (ParentProductId, ChildProductId, Optional, Quantity) VALUES ('B3F755BF-9186-4423-EB41-08D577193FE9', 'EEF699E3-9E1B-4E4C-EB40-08D577193FE9', 0, 1) 它插入正确的值。
  • 根据这个问题,我正在做的事情在技术上应该是可行的。 stackoverflow.com/questions/39728016/…。不知道我哪里出错了。
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 2018-06-02
  • 2019-01-19
  • 1970-01-01
  • 2015-12-20
  • 2017-10-26
  • 1970-01-01
  • 2021-12-29
相关资源
最近更新 更多