如何制作ViewBag显示类的属性?

时间:2017-09-09 05:06:22

标签: c# asp.net .net asp.net-core-mvc dapper

我有两个模特(Ninja& Dojo)。

他们是一对多的关系(忍者属于One Dojo,而Dojo可以拥有许多Ninjas)。

我正在使用Dapper。

Ninja.cs

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

Ninjafactory:

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; }

}
}

Dojo.cs

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

在我的控制器中,

我有:

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

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

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

在我的cshtml中,

function myonFormSubmit(e) 
{
    var ts=e.values[0];
    runQuery("INSERT INTO `TABLENAME` (`timestamp`,....) VALUES ('ts')");
}


function runQuery(qry)//This is pretty bare bones as it has no error handling built in.  I removed it from a much more complicated function. Which you can find in the link in the text below.
{
    var address='address';  
    var user='user';
    var userPwd='pass';
    var db='db';
    var dbUrl='jdbc:mysql://' + address + '/' + db;
    var conn=Jdbc.getConnection(dbUrl, user, userPwd);
    var stmt=conn.prepareStatement(qry)
    stmt.execute();
}

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

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

如何使用ViewBag创建属于Ninja类的Dojo类的属性?

提前非常感谢你。

2 个答案:

答案 0 :(得分:1)

根据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;});

答案 1 :(得分:1)

此代码存在一些问题。 Dojos没有装,你不会处理Ronins(没有Dojos / masters的忍者/武士)。

正如@peinearydevelopment所解释的那样,Dapper并不像自己的全功能ORM那样自动加载相关对象。您必须在一行中返回两个对象,例如使用JOIN并使用multi-mapping将不同的字段映射到不同的对象。

你可以写:

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 ,它返回带有Dojos的Ninjas,并映射到它,例如:

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

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

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

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

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

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

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

//View
@model IEnumerable<Ninja>


@foreach(var ninja in Model)

或作为ViewModel类的一部分:

 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)