以特殊格式显示相关数据

时间:2018-03-06 09:42:18

标签: c# asp.net-mvc entity-framework linq asp.net-core

在ASP的世界里肯定是新的,在下面的例子中发现自己迷失了。显然需要专家来引导。

有两个模特团队&具有以下数据库结构的锦标赛:

public class Tournament
{
    [Key]
    public string TournamentID { get; set; }
    public DateTime TournamentDate { get; set; }
    public string Place { get; set; }

    [ForeignKey("TeamA")]
    public string TeamAID { get; set; }
    public Team TeamA { get; set; }

    [ForeignKey("TeamB")]
    public string TeamBID { get; set; }
    public Team TeamB { get; set; }
}

public class Team
{
    [Key]
    public string TeamID { get; set; }
    public string TeamName { get; set; }
    public string Captain { get; set; }

    [InverseProperty("TeamA")]
    public virtual ICollection<Tournament> TeamA { get; set; }

    [InverseProperty("TeamB")]
    public virtual ICollection<Tournament> TeamB { get; set; }
}

因为锦标赛有两个小组因此使用InverseProperty和外键来建立关系。

然而,因为我试图将结果带回来:

  1. 团队详情;

  2. 以下列格式显示竞争对手的锦标赛列表:

  3. TeamID

    TeamName

    CaptainName

    TournamentID | TournamentDate | TournamentPlace |竞争者

    ...

    ...

    ...

    因此,使用如下的辅助模型:

    public class TeamVM
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public string Captain { get; set; }
        public virtual IEnumerable<TournamentVM> Tournaments { get; set; }
    }
    public class TournamentVM
    {
        public string ID { get; set; }
        public DateTime Date { get; set; }
        public string Place { get; set; }
        public string Competitor { get; set; }
    }
    

    并使用如下控制器映射数据库相关表中的值:

    public async Task<IActionResult> TheAction(string id)
    {
        Team team = await _context.Teams.Where(x => x.TeamID == id).Include(x => x.TeamA).Include(x => x.TeamB).SingleOrDefaultAsync();
    
        TeamVM model = new TeamVM
        {
            ID = team.TeamID,
            Name = team.TeamName,
            Captain = team.Captain,
            Tournaments = team.TeamA.Where(x => x.TeamAID == team.TeamID).Select(x => new TournamentVM
            {
                ID = x.TournamentID,
                Date = x.TournamentDate,
                Place = x.Place,
                Competitor = x.TeamB.TeamName
            }).Concat(team.TeamB.Where(x => x.TeamBID == team.TeamID).Select(x => new TournamentVM
            {
                ID = x.TournamentID,
                Date = x.TournamentDate,
                Place = x.Place,
                Competitor = x.TeamA.TeamName
            })).OrderBy(x => x.Date)
        };
        return View(model);
    }
    

    但结果却是抱怨:

    NullReferenceException:对象引用未设置为对象的实例。

    enter image description here

    因此突出显示部分:

    Tournaments = team.TeamA.Where(x => x.TeamAID == team.TeamID).Select(x => new TournamentVM
        {
            ID = x.TournamentID,
            Date = x.TournamentDate,
            Place = x.Place,
            Competitor = x.TeamB.TeamName
        }).Concat(team.TeamB.Where(x => x.TeamBID == team.TeamID).Select(x => new TournamentVM
        {
            ID = x.TournamentID,
            Date = x.TournamentDate,
            Place = x.Place,
            Competitor = x.TeamA.TeamName
        })).OrderBy(x => x.Date)
    

    尝试了相当多的时间终于让我发现,当发生上述错误时,如果我将上述部分修改为:

    Tournaments = team.TeamA.Where(x => x.TeamAID == team.TeamID).Select(x => new TournamentVM
        {
            ID = x.TournamentID,
            Date = x.TournamentDate,
            Place = x.Place,
            Competitor = x.TeamA.TeamName //i.e. TeamA instead of TeamB
        }).Concat(team.TeamB.Where(x => x.TeamBID == team.TeamID).Select(x => new TournamentVM
        {
            ID = x.TournamentID,
            Date = x.TournamentDate,
            Place = x.Place,
            Competitor = x.TeamB.TeamName //i.e. TeamB instead of TeamA
        })).OrderBy(x => x.Date)
    

    结果显示。

    因此,我不能只提供参赛者的名字,而只能提供球队自己的名字。换句话说,TeamA的部分无法为竞争对手提供TeamB.TeamName。

    可能是什么原因和解决办法?

    对视图使用以下代码:

    @model TeamVM
    <div>@Model.ID</div>
    <div>@Model.Name</div>
    <div>@Model.Captain</div>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Date</th>
                <th>Place</th>
                <th>Competitor</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Tournaments)
            {
                <tr>
                    <td>@item.ID</td>
                    <td>@item.Date</td>
                    <td>@item.Place</td>
                    <td>@item.Competitor</td>
                </tr>
            }
        </tbody>
    </table>
    

    期待并感谢您的专业意见。

    提前致谢。

2 个答案:

答案 0 :(得分:0)

我想建议另一种方法来解决这个问题,因为你的设置听起来有点令人困惑。

您可以简化:

//The same
public class Tournament
{
    [Key]
    public string TournamentID { get; set; }
    public DateTime TournamentDate { get; set; }
    public string Place { get; set; }

    [ForeignKey("TeamA")]
    public string TeamAID { get; set; }
    public Team TeamA { get; set; }

    [ForeignKey("TeamB")]
    public string TeamBID { get; set; }
    public Team TeamB { get; set; }
}

public class Team
{
    [Key]
    public string TeamID { get; set; }
    public string TeamName { get; set; }
    public string Captain { get; set; }

    //Instead of these two
    //[InverseProperty("TeamA")]
    //public virtual ICollection<Tournament> TeamA { get; set; }

    //[InverseProperty("TeamB")]
    //public virtual ICollection<Tournament> TeamB { get; set; }

    //Let's just include the tournaments this team participated in
    public virtual ICollection<Tournament> Tournaments { get; set; }
}

现在,您可以使用Tournaments拨打Include()

public async Task<IActionResult> TheAction(string id)
{
    Team team = await _context.Teams.SingleOrDefaultAsync(x => x.TeamID == id).Include(t => t.Tournaments);

    //You should be able to eager load the teams at this point since you don't use virtual, put a break point to check. If not, you can load them using .ThenInclude()

    TeamVM model = new TeamVM
    {
        ID = team.TeamID,
        Name = team.TeamName,
        Captain = team.Captain,
        Tournaments = team.Tournaments.Select(tournament => new TournamentVM() 
        {
            ID = tournament.TournamentID,
            Date = tournament.TournamentDate,
            Place = tournament.Place,
            Competitor = (tournament.TeamA == team) ? tournament.TeamB.Name : tournament.TeamA.TeamName
            //pick the other team as competitor
        }).OrderBy(x => x.Date)
    };
    return View(model);
}

我自己没有测试过代码,所以欢迎您将其视为伪代码。让我知道结果。

答案 1 :(得分:0)

雅虎!

最后,我确实找到了解决方案。

哇!这个ASP核心世界太棒了!

感谢@Mithgroth的建议,但不能偏离数据库模型。但是,如果可以建议任何进一步的干净版本,我将非常感谢,只要数据库结构保持不变。

无论如何,我在24小时后完成的解决方案是更新的控制器操作,如下所示,其余部分继续保持不变:

public async Task<IActionResult> TheAction(string id){
Team team = await _context.Teams.Where(x => x.TeamID == id).Include(x => x.TeamA).Include(x => x.TeamB).SingleOrDefaultAsync();

var gamesList = (from x in _context.Tournaments
                    .Where(x => x.TeamAID == id || x.TeamBID == id)
                    select new TournamentVM
                    {
                        ID = x.TournamentID,
                        Date = x.TournamentDate,
                        Place = x.Place,
                        Competitor = x.TeamAID == id ? x.TeamB.TeamName : x.TeamA.TeamName
                    });

TeamVM model = new TeamVM
{
    ID = team.TeamID,
    Name = team.TeamName,
    Captain = team.Captain,
    Tournaments = from x in gamesList
        .Select(x => new TournamentVM
        {
            ID = x.ID,
            Date = x.Date,
            Place = x.Place,
            Competitor = x.Competitor
        }).OrderBy(x => x.Date) select x
};
return View("TheAxion", model);}

: - )