【问题标题】:How to join two table in C# web API如何在 C# Web API 中加入两个表
【发布时间】:2021-12-24 23:52:36
【问题描述】:

我是 C# 实体框架的新手。我正在尝试构建 API,但卡在从关系表中检索数据。
我在 MS SQL 数据库中有一个 pei_crops 表,其中 c_id 是主键。我有另一个名为 pei_pests 的表,其中 p_id 是主键。另一个表是 pei_cropspests,我在其中建立了针对哪种害虫袭击哪种作物的关系。多种害虫可以攻击一种作物,一种害虫可以攻击多种作物。在这个 pei_cropspests 表中,我将 p_id 作为主键和外键,将 c_id 作为主键和外键.

pei_crops 表:

c_id c_name c_description
1 Corn NULL

pei_pests 表:

p_id p_name p_URL
1 pest1 NULL
2 pest2 NULL

pei_cropspests 表:

p_id c_id
1 1
2 1

现在我想在我的 API 中展示类似的东西

[
{
    "cId":1,
    "pests":[
             {
               "pId":1,
               "pName": pest1,
               "pURL": null
             },
             {
               "pId":2,
               "pName": pest2,
               "pURL": null
             }

           ]
}
]

到目前为止,我在 C# Web API 项目中的 get 请求如下所示:

[Route("Getspecific/{cropId}")]
[HttpGet]
public async Task<IActionResult> GetSpecific(int cropId)
{
    var cropDetails = await _db.PeiCrops.Where(c=>c.CId == cropId).Include(i=>i.PeiCropspests).ToListAsync();
    return Ok(cropDetails);
}

此代码仅返回影响 cID 编号 1 的害虫的 pID 和 URL。但我还想要害虫名称和 URL 以及它们的 id。

谁能告诉我怎么做。也许有一些方法可以连接两个表并显示数据?我只是不知道如何在 C# 中做到这一点。任何帮助表示赞赏。谢谢。

实体类: PeiCrop:

using System;
using System.Collections.Generic;

#nullable disable

namespace PEI_API.EF
{
    public partial class PeiCrop
    {
        public PeiCrop()
        {
            PeiCropimages = new HashSet<PeiCropimage>();
            PeiCropsdiseases = new HashSet<PeiCropsdisease>();
            PeiCropspests = new HashSet<PeiCropspest>();
        }

        public int CId { get; set; }
        public string CName { get; set; }
        public string CPhotoUrl { get; set; }
        public string CDescription { get; set; }

        public virtual ICollection<PeiCropimage> PeiCropimages { get; set; }
        public virtual ICollection<PeiCropsdisease> PeiCropsdiseases { get; set; }
        public virtual ICollection<PeiCropspest> PeiCropspests { get; set; }
    }
}

佩佩斯:

using System;
using System.Collections.Generic;

#nullable disable

namespace PEI_API.EF
{
    public partial class PeiPest
    {
        public PeiPest()
        {
            PeiCropspests = new HashSet<PeiCropspest>();
            PeiPestimages = new HashSet<PeiPestimage>();
        }

        public int PId { get; set; }
        public string PName { get; set; }
        public string PPhotoUrl { get; set; }
        public string PDescription { get; set; }

        public virtual ICollection<PeiCropspest> PeiCropspests { get; set; }
        public virtual ICollection<PeiPestimage> PeiPestimages { get; set; }
    }
}

PeiCropspest:

using System.Collections.Generic;

#nullable disable

namespace PEI_API.EF
{
    public partial class PeiCropspest
    {
        public int PId { get; set; }
        public int CId { get; set; }

        public virtual PeiCrop CIdNavigation { get; set; }
        public virtual PeiPest PIdNavigation { get; set; }
    }
}

【问题讨论】:

  • 也许LINQ可以做到?
  • @urlreader 我很困惑,不知道如何将它与我当前的代码集成并将其返回给 API。
  • 你能展示实体类吗?
  • @Sami 使用此站点学习如何询问 SQL,对现在和将来都非常有用:meta.stackoverflow.com/questions/333952/…
  • @LeandroBardelli 感谢您的指出。我已经修好了

标签: c# mysql sql-server entity-framework asp.net-web-api


【解决方案1】:

首先,您需要配置关系:

class MyContext : DbContext
{
    ...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<PeiCropspest>()
            .HasKey(cp => new { cp.PId, cp.CId });

        //Configure one PeiPest to many PeiCropspest
        modelBuilder.Entity<PeiCropspest>()
            // Specify PeiCropspest's navigation property to one PeiPest
            .HasOne(cp => cp.PIdNavigation)
            // Specify PeiPest's navigaton property to many PeiCropspest
            .WithMany(p => p.PeiCropspests)
            // Specify PeiCropspest's navigation property
            // to use this PeiCropspest's property as foreign key
            .HasForeignKey(cp => cp.PId);

        //Configure one PeiCrop to many PeiCropspest
        modelBuilder.Entity<PeiCropspest>()
            // Specify PeiCropspest's navigation shadow property to one PeiCrop
            .HasOne<PeiCrop>()
            // Specify PeiCrop's navigaton property to many PeiCropspest
            .WithMany(c => c.PeiCropspests)
            // Specify PeiCropspest's navigation shadow property
            // to use this PeiCropspest's property as foreign key
            .HasForeignKey(cp => cp.CId);
    }

    public DbSet<PeiCrop> PeiCrops { get; set; }
}

然后你可以在 LINQ 查询中做一个投影:

public async Task<IActionResult> GetSpecific(int cropId)
{
    var cropDetails = await _db.PeiCrops
    .Where(c=>c.CId == cropId)
    .Select(c => new {
        cId = c.CId,
        pests = c.PeiCropspests.Select(p => new {
            pId = p.PIdNavigation.PId,
            pName = p.PIdNavigation.PName,
            pUrl = p.PIdNavigation.PPhotoUrl
        })
    })
    .ToListAsync();
    return Ok(cropDetails);
}

你知道吗?从 EF Core 5 开始,可以在没有中间实体的情况下建立多对多关系。这可以简化您的实体模型。参看。 the documentation

【讨论】:

  • 嘿@vernou 非常感谢你。这个对我有用。
  • 如果这个答案回答了你的问题,你能接受吗?
  • 对不起,这是我的第二篇文章。我不知道答案是否可以接受。接受你的回答
【解决方案2】:

你已经很接近了,但你也没有像你一样完全使用 EF,我的意思是你实际上不必自己制作关系表,而是可以直接从实体 pei_crop 引用实体 pei_pests 的列表让 EF 创建另一个。

//Example just getting one property from each, 
//but you can new a composite return type up if you wish, using select
var cropDetails = await _db.PeiCrops
                            .Where(c=>c.CId == cropId)
                            .Include(i=>i.PeiCropspests)
                            .ThenInclucde(t => t.Pests)
                            .Select(s => new { CropId = s.p_id, PestName = s.PeiCropsPests.Pest.p_name  })
                            .ToListAsync();

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select?view=net-5.0

【讨论】:

  • 我撤回了我的反对票并支持你,因为示例错误,而不是数据。
  • Include 在使用自定义 Select 投影时不需要或使用。
  • 嗨@LeandroBardelli 我已将实体类添加到我的问题中。我试图将您提供的代码添加到我的代码中。我遇到了一些错误。因为有些表是不可访问的。就像在 ThenInclude() t.Pests 上向我显示的错误 ICollection 不包含 'Pests' 的定义。也许是因为我没有向您展示实体类,而您试图给我一个想法。也许我需要更改一些代码
  • @Sami 哦不,答案是为 T. Nielsen 准备的
  • 再次感谢。哈哈。我说错人了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 2018-12-17
  • 2015-04-28
  • 2021-07-23
  • 1970-01-01
  • 2021-06-25
  • 2023-03-10
相关资源
最近更新 更多