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

EF关联两张表:如何将CompetitionId转换为CompetitionName并展示

EF Core实现Rewards与Competitions表内连接并展示CompetitionName

问题背景

我有两张数据库表:Rewards存储核心数据,Competitions存储竞赛名称信息。已经能用SQL内连接查询得到正确结果,现在需要在EF中实现相同逻辑,最终仅展示由CompetitionId转换而来的CompetitionName列。相关代码如下:

参考SQL语句

SELECT Rewards.Id, Rewards.CompetitionId, Competitions.CompetitionName
FROM Rewards
INNER JOIN Competitions
ON Rewards.CompetitionId=Competitions.CompetitionId

现有Model代码

public class Reward
{
    [Required]
    public int Id { get; set; }
    [Display(Name = "Competition")]
    [Required]
    public int CompetitionId { get; set; }
    [Required]
    [Display(Name = "League")]
    public string LeagueId { get; set; }
    [Required]
    [Display(Name = "Game Week")]
    public string GameWeekId { get; set; }
    [Required]
    [Display(Name = "Type")]
    public string CardTypeId { get; set; }
    [Display(Name = "Name")]
    public string? Name { get; set; }
    [Display(Name = "Year")]
    public string? YearId { get; set; }
    [Display(Name = "Number")]
    public string? Number { get; set; }
    [Display(Name = "Comment")]
    public string? Comment { get; set; }
}

public class Competition
{
    public int CompetitionId { get; set; }
    [Display(Name = "Competition Name")]
    public string CompetitionName { get; set; }
}

现有Controller代码

[Authorize]
// GET: Rewards
public async Task<IActionResult> Index(string searchString)
{
    if (_context.Rewards == null)
    {
        return Problem("Entity set 'RewardsContext.Rewards'  is null.");
    }

    var query = from reward in _context.Rewards
                join competition in _context.Competitions
                on reward.CompetitionId equals competition.CompetitionId
                select new
                {
                    reward.Id,
                    competition.CompetitionName
                };

    var rewardsWithTranslatedCompetitionNames = query.ToList();

    return View(rewardsWithTranslatedCompetitionNames);
}

解决方案

1. 优化匿名类型查询(快速适配)

你的LINQ查询逻辑已经正确实现了内连接,和SQL逻辑一致。但要注意视图的模型绑定问题——匿名类型无法直接强类型绑定,需调整视图使用动态模型,或补充Reward的其他字段到匿名类型中:

修改后的Controller代码(补充字段+异步优化):

[Authorize]
// GET: Rewards
public async Task<IActionResult> Index(string searchString)
{
    if (_context.Rewards == null)
    {
        return Problem("Entity set 'RewardsContext.Rewards'  is null.");
    }

    var query = from reward in _context.Rewards
                join competition in _context.Competitions
                on reward.CompetitionId equals competition.CompetitionId
                select new
                {
                    reward.Id,
                    reward.LeagueId,
                    reward.GameWeekId,
                    reward.CardTypeId,
                    reward.Name,
                    reward.YearId,
                    reward.Number,
                    reward.Comment,
                    CompetitionName = competition.CompetitionName
                };

    // 可选:添加搜索功能
    if (!string.IsNullOrEmpty(searchString))
    {
        query = query.Where(r => r.CompetitionName.Contains(searchString) || (r.Name?.Contains(searchString) ?? false));
    }

    var rewardsWithCompetitionNames = await query.ToListAsync();
    return View(rewardsWithCompetitionNames);
}

对应的视图(Index.cshtml)使用动态模型:

@model IEnumerable<dynamic>

<table class="table">
    <thead>
        <tr>
            <th>@Html.DisplayNameFor(model => model.Id)</th>
            <th>@Html.DisplayNameFor(model => model.CompetitionName)</th>
            <th>@Html.DisplayNameFor(model => model.LeagueId)</th>
            <th>@Html.DisplayNameFor(model => model.GameWeekId)</th>
            <!-- 其他需要展示的列 -->
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>@Html.DisplayFor(modelItem => item.Id)</td>
            <td>@Html.DisplayFor(modelItem => item.CompetitionName)</td>
            <td>@Html.DisplayFor(modelItem => item.LeagueId)</td>
            <td>@Html.DisplayFor(modelItem => item.GameWeekId)</td>
            <!-- 其他列展示 -->
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

2. 使用强类型ViewModel(推荐方案)

匿名类型在视图中不够直观,容易出错,推荐创建ViewModel封装需要展示的字段:

首先创建ViewModel:

public class RewardViewModel
{
    public int Id { get; set; }
    [Display(Name = "Competition")]
    public string CompetitionName { get; set; }
    [Display(Name = "League")]
    public string LeagueId { get; set; }
    [Display(Name = "Game Week")]
    public string GameWeekId { get; set; }
    [Display(Name = "Type")]
    public string CardTypeId { get; set; }
    [Display(Name = "Name")]
    public string? Name { get; set; }
    [Display(Name = "Year")]
    public string? YearId { get; set; }
    [Display(Name = "Number")]
    public string? Number { get; set; }
    [Display(Name = "Comment")]
    public string? Comment { get; set; }
}

修改Controller查询逻辑:

[Authorize]
// GET: Rewards
public async Task<IActionResult> Index(string searchString)
{
    if (_context.Rewards == null)
    {
        return Problem("Entity set 'RewardsContext.Rewards'  is null.");
    }

    var query = from reward in _context.Rewards
                join competition in _context.Competitions
                on reward.CompetitionId equals competition.CompetitionId
                select new RewardViewModel
                {
                    Id = reward.Id,
                    CompetitionName = competition.CompetitionName,
                    LeagueId = reward.LeagueId,
                    GameWeekId = reward.GameWeekId,
                    CardTypeId = reward.CardTypeId,
                    Name = reward.Name,
                    YearId = reward.YearId,
                    Number = reward.Number,
                    Comment = reward.Comment
                };

    if (!string.IsNullOrEmpty(searchString))
    {
        query = query.Where(r => r.CompetitionName.Contains(searchString) || (r.Name?.Contains(searchString) ?? false));
    }

    var rewardsWithCompetitionNames = await query.ToListAsync();
    return View(rewardsWithCompetitionNames);
}

对应的强类型视图:

@model IEnumerable<YourNamespace.RewardViewModel>

<table class="table">
    <thead>
        <tr>
            <th>@Html.DisplayNameFor(model => model.Id)</th>
            <th>@Html.DisplayNameFor(model => model.CompetitionName)</th>
            <th>@Html.DisplayNameFor(model => model.LeagueId)</th>
            <th>@Html.DisplayNameFor(model => model.GameWeekId)</th>
            <!-- 其他列 -->
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>@Html.DisplayFor(modelItem => item.Id)</td>
            <td>@Html.DisplayFor(modelItem => item.CompetitionName)</td>
            <td>@Html.DisplayFor(modelItem => item.LeagueId)</td>
            <td>@Html.DisplayFor(modelItem => item.GameWeekId)</td>
            <!-- 其他列 -->
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

3. 添加导航属性(符合EF Core设计规范)

如果允许修改Model,可以给Reward类添加导航属性,简化查询逻辑:

修改Reward Model:

public class Reward
{
    [Required]
    public int Id { get; set; }
    [Required]
    [Display(Name = "Competition")]
    public int CompetitionId { get; set; }
    // 添加导航属性
    public virtual Competition Competition { get; set; }
    // 其他原有属性...
}

查询逻辑简化为:

var query = _context.Rewards
                    .Include(r => r.Competition) // 预加载关联数据
                    .Select(r => new RewardViewModel
                    {
                        Id = r.Id,
                        CompetitionName = r.Competition.CompetitionName,
                        // 其他属性映射
                    });

这种方式更符合EF的ORM设计思想,后续扩展关联数据查询会更便捷。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:20:03