如何让 ViewBag 显示 class' 属性?

How do I make ViewBag display class' property?

我有两个模型(忍者和道场)。

他们是一对多的关系(忍者属于一个道场,而道场可以有多个忍者)。

我正在使用 Dapper。

Ninja.cs

using System.ComponentModel.DataAnnotations;
using dojoleague.Models;
using System;

namespace dojoleague.Models {
public class Ninja : BaseEntity{

    [Key]
    public long Id {get; set;}

    [Required(ErrorMessage="You need a name!")]
    public string Name {get; set;}

    [Range(1,11, ErrorMessage="Must be between 1 and 10")]
    public int Level {get; set;}

    [Required]
    public Dojo Dojo {get; set;}

    public string Description {get; set;}


  }
}

忍者工厂:

public IEnumerable<Ninja> FindAll() 
{ 
    using (IDbConnection dbConnection = Connection) 
    { 
        dbConnection.Open(); 
        return dbConnection.Query<Ninja>("SELECT * FROM ninjas"); 
    } 
} 

Dojo.cs

using System.ComponentModel.DataAnnotations;
using System;
using System.Collections.Generic;

namespace dojoleague.Models {
public class Dojo : BaseEntity{

    [Key]
    public long Id {get; set;}

    [Required]
    public string Name {get; set;}

    [Required(ErrorMessage="We have to know where it is")]
    public string Location {get; set;}

    [Required(ErrorMessage="Provide additional info on the Dojo")]
    public string Description {get; set;}

     public ICollection<Ninja> Ninjas { get; set; }

}
}

在我的控制器中,

我有:

 ninjaFactory.Add(newNinja, dojo);
 System.Console.WriteLine(newNinja.Dojo.Name);
 ViewBag.Ninja = ninjaFactory.FindAll();
 return View();

现在,System.Console.WriteLine(newNinja.Dojo.Name) 在控制台中正确打印出 Dojo 的名称。

但是,它没有在我的网络浏览器上显示 Dojo 的名称。

在我的 cshtml 中,

@{
  foreach(var ninja in ViewBag.Ninja){
      <h2>@ninja.Name</h2>
      <h4>@ninja.Dojo.Name</h4>
   }
 }

它确实打印出@ninja.Name 但它没有打印出@ninja.Dojo.Name 说

RuntimeBinderException: 无法对空引用执行运行时绑定

如何使用 ViewBag 显示属于 Ninja class 的道场 class 的属性??

在此先感谢您。

根据 documentation,您似乎需要将查询更新为: var sql = @"select * from #Ninjas n left join #Dojos d on d.Id = n.DojoId Order by n.Id";

return dbConnection.Query<Post, Dojo>(sql, (ninja, dojo)=> { ninja.Dojo = dojo; return ninja;});

这段代码有几个问题。道场未加载,您不处理浪人(ninjas/samurais 没有 Dojos/masters)。

正如@peinearydevelopment 所解释的那样,Dapper 不会像 full-featured ORM 那样自动加载相关 objects。您必须在一行中同时 return 和 objects,例如使用 JOIN 并使用 multi-mapping 将不同的字段映射到不同的 objects。

你可以这样写:

var sql ="SELECT * FROM ninjas inner join Dojos on Ninjas.DojoID=Docos.ID";
dbConnection.Query<Ninja, Dojo, Ninja>(sql, (ninja, dojo) => 
    { 
        ninja.Dojo = dojo; 
        return ninja;
    });

更好的选择是创建一个 View,returns Ninjas with Dojos,并映射到它,例如:

var sql ="SELECT * FROM ninjasWithDojos ...";
dbConnection.Query<Ninja, Dojo, Ninja>(sql, (ninja, dojo) => 
    { 
        ninja.Dojo = dojo; 
        return ninja;
    });

问题的另一部分是忍者可能没有道场。如果您使用内部联接,您甚至无法加载此类条目。您可以使用左外连接加载 Ronins :

var sql ="SELECT * FROM ninjas left outer join Dojos on Ninjas.DojoID=Docos.ID";

在这种情况下,您必须更改 MVC 视图循环以忽略空值。您可以检查 Dojo 并完全删除 header,或者呈现不同的片段:

@foreach(var ninja in Model.Ninja)
{
    <h2>@ninja.Name</h2>
    @if (ninja.Dojo != null)
    {       
       <h4>@(ninja?.Dojo?.Name)??"Ronin!"</h4>
    }
}

请注意,我使用 Model 而不是 ViewBag。编写和调试强类型视图要容易得多。您可以直接从您的控制器 return 忍者 :

//Controller
 var ninjas= ninjaFactory.FindAll();
 return View(ninjas);

//View
@model IEnumerable<Ninja>


@foreach(var ninja in Model)

或者作为 ViewModel 的一部分 class :

 var ninjas= ninjaFactory.FindAll();
 var villains = ...;
 var game = new GameModel { Ninjas = ninjas, Villains = villains};
 return View(game);

//View
@model GameModel


@foreach(var ninja in Model.Ninjas)