2017-09-09 1 views
1

J'ai deux modèles (Ninja & Dojo).Comment faire pour que ViewBag affiche la propriété de la classe?

Ils sont une relation à plusieurs (Ninja appartient à One Dojo alors que Dojo peut avoir beaucoup de Ninjas).

J'utilise 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;} 


    } 
} 

Ninjafactory:

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

} 
} 

Dans mon contrôleur,

Je:

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

Maintenant, System.Console.WriteLine (newNinja.Dojo.Name) affiche correctement le nom de Dojo dans la console.

Cependant, il ne montre pas le nom de Dojo sur mon navigateur Web.

Dans mon cshtml,

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

Il n'imprime sur @ ninja.Name mais il n'imprime pas @ ninja.Dojo.Name dire

RuntimeBinderException: Impossible d'effectuer la liaison d'exécution sur un null référence

Comment faire l'attribut de la classe Dojo qui appartient à la classe Ninja en utilisant ViewBag ??

Merci beaucoup d'avance.

+0

Pouvez-vous écrire votre méthode 'ninjaFactory.FindAll()'? – Kahbazi

+0

public IEnumerable FindAll() { utilisant (IDbConnection dbConnection = Connexion) { dbConnection.Open(); return dbConnection.Query ("SELECT * FROM ninjas"); } } – Jung

+0

Ceci n'a rien à voir avec MVC ou viewbag. Le message d'erreur explique ce qui ne va pas. La propriété 'Dojo' est au moins * null *. * Y a-t-il un Dojo à afficher? À quoi ressemblent les données? –

Répondre

1

Il y a quelques problèmes avec ce code. Les Dojos ne sont pas chargés et vous ne manipulez pas les Ronins (ninjas/samouraïs sans Dojos/maîtres). Comme l'explique @peinearydevelopment, Dapper ne charge pas automatiquement les objets associés comme les ORM complets. Vous devrez retourner les deux objets dans une seule ligne, par exemple avec un JOIN et utiliser multi-mapping pour mapper différents champs à différents objets.

Vous pouvez écrire:

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

Une option encore mieux serait de créer un Voir qui retourne Ninjas avec dojos, et la carte à elle, par exemple:

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

L'autre partie du problème est qu'un Ninja ne peut avoir un Dojo. Vous ne pourrez même pas charger de telles entrées si vous utilisez une jointure interne.Vous pouvez charger Samouraïs en utilisant une jointure externe gauche:

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

Dans ce cas, vous devez changer votre boucle MVC Voir d'ignorer les valeurs NULL. Vous pouvez vérifier le Dojo et de supprimer l'en-tête entièrement, ou rendre un autre extrait:

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

Notez que j'utilise Model au lieu de ViewBag. Il est beaucoup plus facile d'écrire et de déboguer une vue fortement typée. Vous pouvez retourner les ninjas directement à partir de votre contrôleur:

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

//View 
@model IEnumerable<Ninja> 


@foreach(var ninja in Model) 

ou dans le cadre d'une classe 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) 
1

Selon le documentation, il semblerait que vous devez mettre à jour votre requête à ceci: 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

Les docs disent que vous devez retourner le 'Dojos' dans une jointure –

+0

@PanagiotisKanavos Yup, j'ai oublié d'inclure la requête SQL réelle. Mis à jour, merci! – peinearydevelopment