You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.Net 7电商项目ProductCategories中间表无法填充技术问询

.NET 7 多对多关联表ProductCategories无法填充的问题修复

我在跟着Udemy课程开发电商网站时,为实现Products和Categories的多对多关联创建了ProductCategories表。目前数据库已成功生成该表,Products表也能正常添加数据,但ProductCategories表始终无法被填充。使用的是.NET 7.0.102版本,相关代码如下:

实体类代码

Category.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace shopapp.entity
{
    public class Category
    {
        public int CategoryId { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public List<ProductCategory> ProductCategories { get; set; }
    }
}

Product.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace shopapp.entity
{
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; } 
        public double Price { get; set; } 
        public string Description { get; set; } 
        public string ImageUrl { get; set; }
        public bool IsApproved { get; set; }
        public int CategoryId { get; set; } // 冗余字段,需删除
        public List<ProductCategory> ProductCategories { get; set; }
    }
}

ProductCategory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace shopapp.entity
{
    public class ProductCategory
    {
        public int CategoryId { get; set; }
        public Category Category { get; set; }
        public int ProductId { get; set; }
        public Product Product { get; set; }
    }
}

DbContext配置代码

ShopContext.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using shopapp.entity;

namespace shopapp.data.Concrete.EfCore
{
    public class ShopContext:DbContext
    {
        public DbSet<Product> Products { get; set; }
        public DbSet<Category> Categories { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySQL("Server=localhost;port=3306;Database=shopapp2;Uid=root;Pwd=admin;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 原配置外键颠倒,需修正
            modelBuilder.Entity<ProductCategory>()
            .HasOne(pc => pc.Category)
            .WithMany(pc => pc.ProductCategories)
            .HasForeignKey(pc => pc.ProductId);

            modelBuilder.Entity<ProductCategory>()
            .HasOne(pc => pc.Product)
            .WithMany(pc => pc.ProductCategories)
            .HasForeignKey(pc => pc.CategoryId);
        }
    }   
}

数据初始化(Seed)代码

SeedDatabase.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using shopapp.entity;

namespace shopapp.data.Concrete.EfCore
{
    public static class SeedDatabase
    {
        public static void Seed()
        {
            using(var context = new ShopContext())
            {
                if (context.Database.GetPendingMigrations().Count() == 0)
                {
                    if (context.Categories.Count() == 0)
                    {
                        context.Categories.AddRange(Categories);
                    }

                    if (context.Products.Count() == 0)
                    {
                        context.Products.AddRange(Products);
                        context.AddRange(ProductCategories); // 逻辑依赖Products判断,存在漏洞
                    }
                    context.SaveChanges();
                }
            }
            
        }

        private static Category[] Categories = {
            new Category(){ CategoryId=4, Name = "Fashion", Description="Fashion Category"},
            new Category(){ CategoryId=5, Name = "Supermarket", Description="Supermarket Category"},
            new Category(){ CategoryId=6, Name = "Mom and Baby", Description="Mom and Baby Category"}
        };

        private static Product[] Products = {
            new Product(){ProductId=11, Name = "Test Product 1", Price=1000, Description="Test Data", ImageUrl="test.jpg", IsApproved=true},
            new Product(){ProductId=12, Name = "Test Product 2", Price=1200, Description="Test Data", ImageUrl="test.jpg", IsApproved=true},
            new Product(){ProductId=13, Name = "Test Product 3", Price=1400, Description="Test Data", ImageUrl="test.jpg", IsApproved=false}
            
        };

        private static ProductCategory[] ProductCategories = 
        {
            // 重复条目+关联不匹配,需修正
            new ProductCategory(){CategoryId = Categories[0].CategoryId, Category=Categories[0], ProductId = Products[0].ProductId, Product=Products[2]},
            new ProductCategory(){CategoryId = Categories[0].CategoryId, Category=Categories[0], ProductId = Products[0].ProductId, Product=Products[2]},
            new ProductCategory(){CategoryId = Categories[0].CategoryId, Category=Categories[0], ProductId = Products[0].ProductId, Product=Products[2]}
        };
    }
}

问题修复步骤

1. 修正DbContext的关联配置

外键配置完全颠倒,且缺少复合主键设置,修改OnModelCreating方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 设置复合主键
    modelBuilder.Entity<ProductCategory>()
        .HasKey(pc => new { pc.ProductId, pc.CategoryId });

    // 正确配置Category关联
    modelBuilder.Entity<ProductCategory>()
        .HasOne(pc => pc.Category)
        .WithMany(c => c.ProductCategories)
        .HasForeignKey(pc => pc.CategoryId);

    // 正确配置Product关联
    modelBuilder.Entity<ProductCategory>()
        .HasOne(pc => pc.Product)
        .WithMany(p => p.ProductCategories)
        .HasForeignKey(pc => pc.ProductId);
}

2. 删除Product实体中的冗余字段

移除Product.cs中的public int CategoryId { get; set; },避免和多对多关联冲突。

3. 修正Seed数据的ProductCategories

删除重复条目,确保ProductId和关联的Product实例匹配,无需手动赋值Category/Product属性:

private static ProductCategory[] ProductCategories = 
{
    new ProductCategory(){CategoryId = Categories[0].CategoryId, ProductId = Products[0].ProductId},
    new ProductCategory(){CategoryId = Categories[0].CategoryId, ProductId = Products[1].ProductId},
    new ProductCategory(){CategoryId = Categories[1].CategoryId, ProductId = Products[0].ProductId},
    new ProductCategory(){CategoryId = Categories[2].CategoryId, ProductId = Products[2].ProductId}
};

4. 调整Seed逻辑

将ProductCategories的添加逻辑独立,避免依赖Products的判断分支:

public static void Seed()
{
    using(var context = new ShopContext())
    {
        if (context.Database.GetPendingMigrations().Count() == 0)
        {
            if (context.Categories.Count() == 0)
            {
                context.Categories.AddRange(Categories);
            }

            if (context.Products.Count() == 0)
            {
                context.Products.AddRange(Products);
            }

            // 独立判断中间表是否需要初始化
            if (context.Set<ProductCategory>().Count() == 0)
            {
                context.AddRange(ProductCategories);
            }

            context.SaveChanges();
        }
    }
}

内容的提问来源于stack exchange,提问作者akoluacik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:30:58