C# EF Core-指定自己的外键时自动添加不需要的外键

C# EF Core-指定自己的外键时自动添加不需要的外键,c#,entity-framework-core,.net-5,C#,Entity Framework Core,.net 5,在我的GroceryItemGroceryStores多对多联接表中似乎有重复的外键:VeganItemId,VeganItemsId,机构id,机构sid 我实际上只使用了VeganItemId和estitmentid,它们是唯一被添加到中的。它会自动将VeganItemsId和buildmentsid列添加到我的表中。我怎么告诉它不要 我的数据库的此图像显示了有效的外键: 我的数据库上下文: modelBuilder.Entity<GroceryItem>(gi =>

在我的
GroceryItemGroceryStores
多对多联接表中似乎有重复的外键:
VeganItemId
VeganItemsId
机构id
机构sid

我实际上只使用了
VeganItemId
estitmentid
,它们是唯一被添加到中的。它会自动将
VeganItemsId
buildmentsid
列添加到我的表中。我怎么告诉它不要

我的数据库的此图像显示了有效的外键:

我的数据库上下文:

modelBuilder.Entity<GroceryItem>(gi =>
{
    gi.HasIndex(e => new { e.Brand, e.Name }).IsUnique();
    gi.HasKey(e => e.Id);
    gi.Property(e => e.Tags)
    .HasConversion(
        v => JsonSerializer.Serialize(v, null),
        v => JsonSerializer.Deserialize<List<GroceryItemTag>>(v, null),
        new ValueComparer<IList<GroceryItemTag>>(
            (c1, c2) => c1.SequenceEqual(c2),
            c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
            c => (IList<GroceryItemTag>)c.ToList()));

});

modelBuilder.Entity<GroceryStore>(gs =>
{
    gs.HasIndex(gs => gs.PlaceId).IsUnique();

    gs.HasMany(gs => gs.VeganItems)
    .WithMany(vi => vi.Establishments)
    .UsingEntity<GroceryItemGroceryStore>
        (gigs => gigs.HasOne<GroceryItem>().WithMany(),
        gigs => gigs.HasOne<GroceryStore>().WithMany());
});

modelBuilder.Entity<GroceryItemGroceryStore>(gigs =>
{
    gigs.HasIndex(e => new { e.VeganItemId, e.EstablishmentId }).IsUnique();
    gigs.HasKey(e => new { e.VeganItemId, e.EstablishmentId });
});

public DbSet<GroceryItem> GroceryItems { get; set; }
public DbSet<GroceryItemGroceryStore> GroceryItemGroceryStores { get; set; }
public DbSet<GroceryStore> GroceryStores { get; set; }
使表格具有
VeganItemId1
设施ID1


编辑:此后,我尝试从所有迁移文件中删除所有出现的
VeganItemsId
restitmentsid
,但在插入数据库时,它仍然认为需要插入
restitmentsid

此类FKs的存在清楚地表明关系配置错误,并且通常会发生当您从fluent配置中删除一些关系导航属性时,在这种情况下,EF会将它们映射到具有常规FK属性/列名的单独FK关系

在这种特殊情况下,错误配置就在这里

gigs => gigs.HasOne<GroceryItem>().WithMany() // (1)
可能它们最初不存在,而您后来添加了它们。但是您应该始终保持fluent配置与模型同步,在这种情况下,当然应该是

gigs => gigs.HasOne(e => e.VeganItem).WithMany()


此类FK的存在是关系配置错误的明确指示,通常在您从fluent配置中遗漏一些关系导航属性时发生,在这种情况下,EF会将它们映射到具有传统FK属性/列名的单独FK关系

在这种特殊情况下,错误配置就在这里

gigs => gigs.HasOne<GroceryItem>().WithMany() // (1)
可能它们最初不存在,而您后来添加了它们。但是您应该始终保持fluent配置与模型同步,在这种情况下,当然应该是

gigs => gigs.HasOne(e => e.VeganItem).WithMany()


您的问题是,您已将
VeganItemId
buildingid
定义为
GroceryItemGroceryStore
的复合主键的一部分,并与
Id
的人工键结合使用

定义包含表中所有行都已唯一的列的复合键是没有必要的,甚至是适得其反的。如果有一个列对所有记录都是唯一的,并且您要将其包含在主键中,那么您应该将该列用作主键

您的fluent配置与属性配置相冲突,我建议以下内容至少是解决方案的一部分:

public class GroceryItemGroceryStore
{
    [Key]
    public Int64 Id { get; set; }
    [ForeignKey(nameof(VeganItem)), Column(Order = 0), Required]
    public int VeganItemId { get; set; }
    [ForeignKey(nameof(Establishment)), Column(Order = 1), Required]
    public int EstablishmentId { get; set; }

    public virtual GroceryItem VeganItem { get; set; }
    public virtual GroceryStore Establishment { get; set; }

    [Required]
    public int NotInEstablishmentCount { get; set; }
    [Required]
    public int InEstablishmentCount { get; set; }
    [Required]
    public double Price { get; set; }

}

您的问题是,您已将
VeganItemId
buildingid
定义为
GroceryItemGroceryStore
的复合主键的一部分,并与
Id
的人工键结合使用

定义包含表中所有行都已唯一的列的复合键是没有必要的,甚至是适得其反的。如果有一个列对所有记录都是唯一的,并且您要将其包含在主键中,那么您应该将该列用作主键

您的fluent配置与属性配置相冲突,我建议以下内容至少是解决方案的一部分:

public class GroceryItemGroceryStore
{
    [Key]
    public Int64 Id { get; set; }
    [ForeignKey(nameof(VeganItem)), Column(Order = 0), Required]
    public int VeganItemId { get; set; }
    [ForeignKey(nameof(Establishment)), Column(Order = 1), Required]
    public int EstablishmentId { get; set; }

    public virtual GroceryItem VeganItem { get; set; }
    public virtual GroceryStore Establishment { get; set; }

    [Required]
    public int NotInEstablishmentCount { get; set; }
    [Required]
    public int InEstablishmentCount { get; set; }
    [Required]
    public double Price { get; set; }

}
  • GroceryItemGroceryStore
    中,将
    VeganItemId
    estitmentid
    的类型更改为
    Int64
    ,以便它们与
    GroceryItem
    GroceryStore中相应主键的类型相匹配-
  • [列(顺序=0),必填]
    public Int64 VeganItemId{get;set;}//此处不需要Key属性
    [列(顺序=1),必填]
    public Int64-estimentid{get;set;}//此处不需要Key属性
    
  • 修改
    GroceryStore
    的配置,以包括导航属性并显式配置外键-
  • builder.Entity(gs=>
    {
    gs.HasIndex(gs=>gs.PlaceId).IsUnique();
    gs.HasMany(gs=>gs.VeganItems)
    .有许多(vi=>vi.机构)
    .商业实体
    (gigs=>gigs.HasOne(p=>p.VeganItem)
    .WithMany().HasForeignKey(p=>p.VeganItemId),
    gigs=>gigs.HasOne(p=>p.Establish)
    .WithMany().HasForeignKey(p=>p.EstationId));
    });
    
    这将解决重复密钥的问题

    另外,您应该从
    GroceryItemGroceryStore
    -

    [Key]
    public Int64 Id { get; set; }
    
    因为您正在通过fluent API配置复合主键

  • GroceryItemGroceryStore
    中,将
    VeganItemId
    estitmentid
    的类型更改为
    Int64
    ,以便它们与
    GroceryItem
    GroceryStore中相应主键的类型相匹配-
  • [列(顺序=0),必填]
    public Int64 VeganItemId{get;set;}//此处不需要Key属性
    [列(顺序=1),必填]
    public Int64-estimentid{get;set;}//此处不需要Key属性
    
  • 修改
    GroceryStore
    的配置,以包括导航属性并显式配置外键-
  • builder.Entity(gs=>
    {
    gs.HasIndex(gs=>gs.PlaceId).IsUnique();
    gs.HasMany(gs=>gs.VeganItems)
    .有许多(vi=>vi.机构)
    .商业实体
    (gigs=>gigs.HasOne(p=>p.VeganItem)
    .WithMany().HasForeignKey(p=>p.VeganItemId),
    gigs=>gigs.HasOne(p=>p.Establish)
    .WithMany().HasForeignKey(p=>p.EstationId));
    });
    
    public class GroceryItemGroceryStore
    {
        [Key]
        public Int64 Id { get; set; }
        [ForeignKey(nameof(VeganItem)), Column(Order = 0), Required]
        public int VeganItemId { get; set; }
        [ForeignKey(nameof(Establishment)), Column(Order = 1), Required]
        public int EstablishmentId { get; set; }
    
        public virtual GroceryItem VeganItem { get; set; }
        public virtual GroceryStore Establishment { get; set; }
    
        [Required]
        public int NotInEstablishmentCount { get; set; }
        [Required]
        public int InEstablishmentCount { get; set; }
        [Required]
        public double Price { get; set; }
    
    }
    
    [Key]
    public Int64 Id { get; set; }