2011-03-27 8 views
2

Bien que j'aime ce que j'apprends, je trouve qu'il est une lutte et ont besoin d'aideDébutant EF4/CodeFirst/MVC3 aide

Je me sers de ces deux tutoriels que je pense sont impressionnants: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx http://msdn.microsoft.com/en-us/data/gg685467

Actuellement, mon principal problème/confusion est:

J'ai une table CodeFirst/entité Je ne sais pas comment correctement les données d'autres tables/entités à afficher dans mes vues:

public class Car { 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public int EngineID { get; set; } 
    public virtual Engine { get; set; } 
} 

public class Engine { 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string Manufacturer { get; set; } 
    // (plus a whole lot of other things) 
} 

Maintenant, quand je créer une vue pour les voitures (en utilisant le type option/Liste) Je reçois une belle liste autogenerated

@foreach (var item in Model) { 
<tr> 
    <td>@item.ID</td> 
    <td>@item.Name</td> 
    <td>@item.EngineID</td> 
</tr> 

parfait ... sauf EngineID est la plupart du temps sans valeur pour le spectateur, et je veux pour montrer Engine.Name à la place

donc je suppose que je pourrais utiliser EF lazy loading:

<td>@item.Engine.Name</td> 

Malheureusement, quand j'ai essayé, il dit mon ObjectContext a b een disposé de façon ne peut pas obtenir d'autres données nécessitant une connexion

Alors j'ai essayé d'aller au contrôleur et y compris le Engine.Name

var cars = (from c in db.Cars.Include("Engine.Name") select c; 

Ce qui me dit: Entities.Engine ne déclare pas une propriété de navigation avec le nom 'Nom'

...? Mensonges

Inclure (« moteur ») fonctionne très bien, mais tout ce que je veux est le nom, et inclure (« Engine ») est en train de charger une grande quantité de choses que je ne veux pas

Précédemment dans une telle situation ceci j'ai créé une vue dans la DB pour la voiture qui inclut EngineName aussi bien. Mais avec CodeFirst et mon noobness je n'ai pas trouvé un moyen de le faire

Comment est-ce que je devrais résoudre ce problème?

Je pensais que je pourrais peut-être créer un modèle à peu près identique à l'entité Car, mais ajouter Engine.Name à celui-ci. Ce serait bien que je pourrais réutiliser dans plusieurs endroits, mais je suis à une perte sur la façon de le remplir, etc.

Voulant apprendre TDD aussi bien, mais ce qui précède est déjà moi frustrant: p

Ps Tout autre tutoriel ou élément pratique à lire sera grandement apprécié

Répondre

2

Ce n'est pas un mensonge car vous essayez d'inclure une propriété qui est un 2ème niveau sans vous donner le moyen de naviguer. Si vous laissez EF générer votre DB avec cette structure, il aurait probablement fait une table de navigation appelée quelque chose comme Car_Engine et si vous incluez le nom sans l'objet qu'il a mappé, alors il n'a pas de propriété de navigation dans votre nouvel objet.

La façon simple de contourner cela est d'aller:

(from c in db.Cars.Include("Engine") select new { c, EngineName = c.Engine.Name } 

Si vous obtenez des erreurs de propriété de navigation alors vous pourriez encore besoin de vous assurer que votre cartographient à votre schéma correctement. Cela peut être fait avec des classes EntityTypeConfiguration en utilisant l'API fluide - très puissant. Ceci ne vous aidera pas à taper fortement votre objet de voiture dans MVC. Si vous voulez contourner cela, votre instinct est juste. Il est assez courant d'utiliser des viewmodels qui sont en lecture seule (par conception, pas forcément en lecture seule) des classes qui fournissent des vues simples de vos données.

Personnellement, je garde mon modèle très propre, puis j'ai un autre projet avec viewmodels et un projet de présentation à remplir. J'éviterais d'utiliser des entités qui se chevauchent dans votre modèle de base, car cela pourrait mener à un comportement imprévisible dans le contexte des données et au moins un cauchemar lors de la mise à jour de plusieurs entités (p. En utilisant votre viewmodels, vous pouvez avoir une classe appelée CarSummaryView ou quelque chose avec seulement les données que vous voulez. Cela résout également le problème d'être vulnérable à la surposition ou au sous-dépôt sur votre site. Il peut être peuplé par la requête ci-dessus assez facilement. PS Il y a un tas d'avantages à utiliser les modèles de vue au-delà du fait de ne pas charger les hiérarchies complètes. L'un des plus importants est le bénéfice intrinsèque qu'il vous procure en évitant les scénarios de sur et sous-jacent.

Il y a des tas de façons de mettre en œuvre viewmodels, mais comme un simple exemple de Carview:

public class CarView 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string EngineName { get; set; } 
} 

Cela devrait être seperated clairement de votre modèle d'entité. Dans un grand projet, vous avez un seul projet viewmodels que le présentateur peut renvoyer, mais dans un projet plus petit, vous en avez juste besoin dans la même couche que le code de service.

Pour remplir directement à partir de la requête, vous pouvez effectuer les opérations suivantes

List<CarView> cars = (from c in db.Cars.Include("Engine.Name") select new CarView() { ID = c.ID, Name = c.Name, EngineName = c.Engine.Name }).ToList(); 
+0

Seriez-vous en mesure de me donner un exemple rapide du viewmodel de CarSummaryView et comment le remplir? Aussi, quel est le e dans EngineName = e.Name? Ne pas vouloir vous faire faire tout le travail, c'est juste que les choses ne se connectent pas dans ma tête et essayent de comprendre – mejobloggs

+0

Exemple simple fourni. L'e était une erreur :) Edited that now. – Gats

+0

C'est super merci. En outre, s'avère si vous choisissez le nouveau CarView() comme cela vous n'avez même pas besoin d'utiliser le .Include ("Engine.Name") (sauf si le chargement paresseux a été éteint je suppose?) – mejobloggs