.NET 6实体框架核心:多一对多的关系

发布于 2025-02-03 22:12:41 字数 4267 浏览 2 评论 0原文

我正在使用.NET 6和实体框架Core构建Web API,以连接到SQL Server数据库。基本的东西看起来像是在起作用,但是我无法在模型中建立多一的关系。

考虑数据库中的以下3个表:

products

“在此处输入图像说明”

类别

sdmkf.png“ rel =” nofollow noreferrer“> ”

我创建了3个与这些表相对应的模型,如下所示:

public class Product
{
    [Key]
    public int Id { get; set; }             = 0;
    public string Name { get; set; }        = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string Label { get; set; }       = string.Empty;
    public int Sativa { get; set; }         = 0;
    public int Indica { get; set; }         = 0;

    public ICollection<CategoryProduct> Categories { get; set; } = new HashSet<CategoryProduct>();
}

public class Category
{
    [Key]
    public int Id { get; set; }      = 0;
    public string Name { get; set; } = string.Empty;
    public int Order { get; set; }   = 0;

    public ICollection<CategoryProduct> Products { get; set; } = new HashSet<CategoryProduct>();
}

public class CategoryProduct
{
    public int CategoryId { get; set; }     = 0;
    public Category? Category { get; set; } = null;
    public int ProductId { get; set; }      = 0;
    public Product? Product { get; set; }   = null;
}

我创建了以下dbContext类,以与数据库进行通信:

public class CoffeeshopContext : DbContext
{
    public DbSet<Shop>? Shops { get; set; }                        = null;
    public DbSet<Category>? Categories { get; set; }               = null;
    public DbSet<Product>? Products { get; set; }                  = null;
    public DbSet<Price>? Prices { get; set; }                      = null;
    public DbSet<CategoryProduct>? ProductCategories { get; set; } = null;

    private readonly IConfiguration _configuration;

    public CoffeeshopContext(DbContextOptions<CoffeeshopContext> options, IConfiguration configuration) : base(options)
    {
        _configuration = configuration;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<CategoryProduct>().HasKey(x => new { x.CategoryId, x.ProductId });
        modelBuilder.Entity<CategoryProduct>().HasOne(x => x.Product)
                                              .WithMany(x => x.Categories)
                                              .HasForeignKey(x => x.ProductId);
        modelBuilder.Entity<CategoryProduct>().HasOne(x => x.Category)
                                              .WithMany(x => x.Products)
                                              .HasForeignKey(x => x.CategoryId);
        base.OnModelCreating(modelBuilder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
            optionsBuilder.UseSqlServer(_configuration.GetConnectionString(nameof(CoffeeshopContext)));
    }
}

当我使用Swagger运行项目时在调用和检索产品的端点时,我会得到以下结果:

[
  {
    "id": 3,
    "name": "Ice Cream Bean",
    "description": "Well balanced hybrid with a mood boosting euphoric high and body relaxation. Diesel and citrus aroma with creamy fruity undertones.",
    "label": "CALI STRAIN",
    "sativa": 50,
    "indica": 50,
    "categories": []
  },
  {
    "id": 4,
    "name": "Blue Cheese",
    "description": "Deep relaxing, calming and pain relief. Berry, blue cheese aroma and a creamy taste.",
    "label": "CLASSIC STRAIN",
    "sativa": 20,
    "indica": 80,
    "categories": []
  }
]

因此,端点正在工作并从数据库中检索产品。

但是,由于某种原因,它没有与类别之间的关系(是的,我相信productCategory表中有一些记录来定义产品和类别之间的关系)。我确定我缺少一些东西,但是我看不到它缺少什么。有人可以将我指向如何完成这项工作的正确方向吗?

I'm building a Web API using .NET 6 and Entity Framework Core to connect to a SQL Server database. The basic stuff looks like it's working, but I cannot make the many-to-many relationships in my models work.

Considering the following 3 tables in the database:

Products:

enter image description here

Categories:

enter image description here

CategoryProduct:

enter image description here

I have created 3 models corresponding to these tables as follows:

public class Product
{
    [Key]
    public int Id { get; set; }             = 0;
    public string Name { get; set; }        = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string Label { get; set; }       = string.Empty;
    public int Sativa { get; set; }         = 0;
    public int Indica { get; set; }         = 0;

    public ICollection<CategoryProduct> Categories { get; set; } = new HashSet<CategoryProduct>();
}

public class Category
{
    [Key]
    public int Id { get; set; }      = 0;
    public string Name { get; set; } = string.Empty;
    public int Order { get; set; }   = 0;

    public ICollection<CategoryProduct> Products { get; set; } = new HashSet<CategoryProduct>();
}

public class CategoryProduct
{
    public int CategoryId { get; set; }     = 0;
    public Category? Category { get; set; } = null;
    public int ProductId { get; set; }      = 0;
    public Product? Product { get; set; }   = null;
}

I have created the following DbContext class to communicate with the database:

public class CoffeeshopContext : DbContext
{
    public DbSet<Shop>? Shops { get; set; }                        = null;
    public DbSet<Category>? Categories { get; set; }               = null;
    public DbSet<Product>? Products { get; set; }                  = null;
    public DbSet<Price>? Prices { get; set; }                      = null;
    public DbSet<CategoryProduct>? ProductCategories { get; set; } = null;

    private readonly IConfiguration _configuration;

    public CoffeeshopContext(DbContextOptions<CoffeeshopContext> options, IConfiguration configuration) : base(options)
    {
        _configuration = configuration;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<CategoryProduct>().HasKey(x => new { x.CategoryId, x.ProductId });
        modelBuilder.Entity<CategoryProduct>().HasOne(x => x.Product)
                                              .WithMany(x => x.Categories)
                                              .HasForeignKey(x => x.ProductId);
        modelBuilder.Entity<CategoryProduct>().HasOne(x => x.Category)
                                              .WithMany(x => x.Products)
                                              .HasForeignKey(x => x.CategoryId);
        base.OnModelCreating(modelBuilder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
            optionsBuilder.UseSqlServer(_configuration.GetConnectionString(nameof(CoffeeshopContext)));
    }
}

When I run the project using swagger, I get the following results when calling and endpoint which retrieves the Products:

[
  {
    "id": 3,
    "name": "Ice Cream Bean",
    "description": "Well balanced hybrid with a mood boosting euphoric high and body relaxation. Diesel and citrus aroma with creamy fruity undertones.",
    "label": "CALI STRAIN",
    "sativa": 50,
    "indica": 50,
    "categories": []
  },
  {
    "id": 4,
    "name": "Blue Cheese",
    "description": "Deep relaxing, calming and pain relief. Berry, blue cheese aroma and a creamy taste.",
    "label": "CLASSIC STRAIN",
    "sativa": 20,
    "indica": 80,
    "categories": []
  }
]

So, the endpoint is working and retrieving products from the database.

However, for some reason it does not make the relationship to categories (and yes, I am sure there are records in the ProductCategory table to define the relationship between products and categories). I am sure I am missing something, but I don't see what it is I'm missing. Can someone perhaps point me in the right direction on how to make this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青衫负雪 2025-02-10 22:12:42

我在清楚的答案的帮助下找到了解决方案。安装microsoft.aspnetcore.mvc.newtonsoftjson软件包,然后将建议更改为program.cs 和我的shopscontroller.cs我能够制造调用数据库并检索具有其类别的产品列表。但是,未检索名称订单属性属性尚未检索。

经过一番反复试验,我想出了一种对我有用的解决方案。我对它有所适合我的需求(我并不需要在此响应中为类别order属性)。我所做的是以下内容:我完成了一些新类,将数据库对象映射到没有数据库导航所需的属性。然后,我在products dbContext对象的表中添加了select()。最后,我的终点最终以这样的方式出现:

[HttpGet, Route("~/coffeeshop/products")]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts(int shopid)
{
    if (_context.Products == null)
        return NotFound();

    return await _context.Products
        .Include(x => x.Categories)
        .Include(x => x.Prices)
        .Where(x => x.Prices.Any(y => y.ShopId == shopid))
        .Select(x => new Product()
        {
            Id          = x.Id,
            Name        = x.Name,
            Description = x.Description,
            Label       = x.Label,
            Sativa      = x.Sativa,
            Indica      = x.Indica,
            Categories  = x.Categories.Select(y => new SmallCategory()
            {
                Name  = y.Category.Name,
                Id    = y.CategoryId
            }).ToList(),
            Prices = x.Prices.Where(y => y.ShopId == shopid).Select(z => new SmallPrice()
            {
                Gram1 = z.Gram1,
                Gram2 = z.Gram2,
                Gram5 = z.Gram5
            }).ToList()
        })
        .ToListAsync();
}

该解决方案产生的响应如下:

[
  {
    "id": 4,
    "name": "Blue Cheese",
    "description": "Deep relaxing, calming and pain relief. Berry, blue cheese aroma and a creamy taste.",
    "label": "CLASSIC STRAIN",
    "sativa": 20,
    "indica": 80,
    "categories": [
      {
        "id": 1,
        "name": "weed"
      },
      {
        "id": 4,
        "name": "indica"
      }
    ],
    "prices": [
      {
        "gram1": 15,
        "gram2": 30,
        "gram5": 67.5
      }
    ]
  }
]

它为我提供了特定商店的产品,包括该产品所属的类别,仅显示该特定商店的价格。这正是我希望输出的方式。

I found a solution with the help of Qing Guo's answer. Installing the Microsoft.AspNetCore.Mvc.NewtonsoftJson package and making the suggested change to Program.cs and my ShopsController.cs I was able to make calls to the database and retrieve a list of products with their categories. However, the Name and Order properties of the categories were not being retrieved.

After some trial and error I came up with a solution that worked for me. I finetuned it a bit to suit my needs (I didn't really need the Order property for a Category in this response for example). What I did was the following: I made some new classes to map the database objects to, without the properties needed for database navigation. I then added those in a Select() on the Products table of the DbContext object. In the end my endpoint ended up like this:

[HttpGet, Route("~/coffeeshop/products")]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts(int shopid)
{
    if (_context.Products == null)
        return NotFound();

    return await _context.Products
        .Include(x => x.Categories)
        .Include(x => x.Prices)
        .Where(x => x.Prices.Any(y => y.ShopId == shopid))
        .Select(x => new Product()
        {
            Id          = x.Id,
            Name        = x.Name,
            Description = x.Description,
            Label       = x.Label,
            Sativa      = x.Sativa,
            Indica      = x.Indica,
            Categories  = x.Categories.Select(y => new SmallCategory()
            {
                Name  = y.Category.Name,
                Id    = y.CategoryId
            }).ToList(),
            Prices = x.Prices.Where(y => y.ShopId == shopid).Select(z => new SmallPrice()
            {
                Gram1 = z.Gram1,
                Gram2 = z.Gram2,
                Gram5 = z.Gram5
            }).ToList()
        })
        .ToListAsync();
}

The response this solution produces is as follows:

[
  {
    "id": 4,
    "name": "Blue Cheese",
    "description": "Deep relaxing, calming and pain relief. Berry, blue cheese aroma and a creamy taste.",
    "label": "CLASSIC STRAIN",
    "sativa": 20,
    "indica": 80,
    "categories": [
      {
        "id": 1,
        "name": "weed"
      },
      {
        "id": 4,
        "name": "indica"
      }
    ],
    "prices": [
      {
        "gram1": 15,
        "gram2": 30,
        "gram5": 67.5
      }
    ]
  }
]

It gives me the products for a specific shop, including the categories the product belongs to and only showing the prices for that specific shop. This is exactly how I wanted the output to be.

GRAY°灰色天空 2025-02-10 22:12:42

1.安装软件包microsoft.aspnetcore.mvc.mvc.newtonsoftjson

2.从builder.services.addcontrollers();

builder.Services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
); 

3. In GetProduct Action添加添加添加

        // GET: api/Products
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Product>>> GetProduct()
        {
          if (_context.Products == null)
          {
              return NotFound();
          }
            return await _context.Products.Include(x=>x.Categories).ToListAsync();
        }

​//i.sstatic.net/68t0x.png“ alt =” inter Image Description在此处”>

1.Installing the package Microsoft.AspNetCore.Mvc.NewtonsoftJson

2.Change the below code from builder.Services.AddControllers();

builder.Services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
); 

3.In GetProduct action add .Include(x=>x.Categories)

        // GET: api/Products
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Product>>> GetProduct()
        {
          if (_context.Products == null)
          {
              return NotFound();
          }
            return await _context.Products.Include(x=>x.Categories).ToListAsync();
        }

Result:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文