如何在 C# web API 中加入两个 table
How to join two table in C# web API
我是 C# 新手 entity framework。我正在尝试构建一个 API,但卡在从关系 table.
中检索数据
我在 MS SQL 数据库中有一个 pei_crops table,其中 c_id 是主键。我有另一个 table 叫做 pei_pests,其中 p_id 是主键。另一个 table 是 pei_cropspests,我在其中建立了哪种害虫攻击哪种作物的关系。多种害虫可以攻击一种作物,一种害虫可以攻击多种作物。在这个 pei_cropspests table 我放了 p_id 作为主键和外键,c_id 作为主键和外键。
pei_crops table:
c_id
c_name
c_description
1
Corn
NULL
pei_pests table:
p_id
p_name
p_URL
1
pest1
NULL
2
pest2
NULL
pei_crops害虫table:
p_id
c_id
1
1
2
1
现在在我的API中我想展示类似的东西
[
{
"cId":1,
"pests":[
{
"pId":1,
"pName": pest1,
"pURL": null
},
{
"pId":2,
"pName": pest2,
"pURL": null
}
]
}
]
到目前为止,我的 get 请求在 C# web API 项目中看起来像这样:
[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);
}
此代码 returns 我只有影响 cID 号 1 的害虫的 pID 和 URL。但我还想要害虫名称和 URL 及其 ID。
谁能告诉我怎么做。也许有某种方法可以连接两个 table 并显示数据?我只是不知道如何在 C# 中执行此操作。任何帮助表示赞赏。谢谢。
实体class:
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; }
}
}
你非常接近,但你也没有完全使用 EF,我的意思是你实际上不必自己建立关系 table 但可以直接参考来自实体 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
首先,您需要配置关系:
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);
}
Do you know? From EF Core 5, it's possible to do many to many relationship without intermediary entity. This can simplify your entity model. cf. the documentation
我是 C# 新手 entity framework。我正在尝试构建一个 API,但卡在从关系 table.
中检索数据
我在 MS SQL 数据库中有一个 pei_crops table,其中 c_id 是主键。我有另一个 table 叫做 pei_pests,其中 p_id 是主键。另一个 table 是 pei_cropspests,我在其中建立了哪种害虫攻击哪种作物的关系。多种害虫可以攻击一种作物,一种害虫可以攻击多种作物。在这个 pei_cropspests table 我放了 p_id 作为主键和外键,c_id 作为主键和外键。
pei_crops table:
c_id | c_name | c_description |
---|---|---|
1 | Corn | NULL |
pei_pests table:
p_id | p_name | p_URL |
---|---|---|
1 | pest1 | NULL |
2 | pest2 | NULL |
pei_crops害虫table:
p_id | c_id |
---|---|
1 | 1 |
2 | 1 |
现在在我的API中我想展示类似的东西
[
{
"cId":1,
"pests":[
{
"pId":1,
"pName": pest1,
"pURL": null
},
{
"pId":2,
"pName": pest2,
"pURL": null
}
]
}
]
到目前为止,我的 get 请求在 C# web API 项目中看起来像这样:
[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);
}
此代码 returns 我只有影响 cID 号 1 的害虫的 pID 和 URL。但我还想要害虫名称和 URL 及其 ID。
谁能告诉我怎么做。也许有某种方法可以连接两个 table 并显示数据?我只是不知道如何在 C# 中执行此操作。任何帮助表示赞赏。谢谢。
实体class: 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; }
}
}
你非常接近,但你也没有完全使用 EF,我的意思是你实际上不必自己建立关系 table 但可以直接参考来自实体 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
首先,您需要配置关系:
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);
}
Do you know? From EF Core 5, it's possible to do many to many relationship without intermediary entity. This can simplify your entity model. cf. the documentation