如何在 C# Web API 中加入两个表
Posted
技术标签:
【中文标题】如何在 C# Web API 中加入两个表【英文标题】:How to join two table in 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.***.com/questions/333952/… @LeandroBardelli 感谢您的指出。我已经修好了 【参考方案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以上是关于如何在 C# Web API 中加入两个表的主要内容,如果未能解决你的问题,请参考以下文章