2012-06-21 2 views
5

Ich komme zu asp.net MVC 4 von einem Hintergrund in Rails, und ich habe einige Schwierigkeiten herauszufinden, wie man mit verschachtelten Modellen umzugehen.ASP.NET MVC 4 - Verschachtelte Modelle - Wie richten Sie die richtigen Assoziationen ein?

Ich verwende Entity Framework 4.3 mit einem CodeFirst-Ansatz.

Die Anwendung ist recht einfach und hat ein Set Modell - das viele Franchises hat. Und es hat ein Franchise-Modell - das zu Sets gehört.

Die POCO-Klassen wurden zusammen mit den entsprechenden Navigationseigenschaften erstellt, dann habe ich die Controller mit den Ansichten gerüstet und dann die Datenbank generiert.

Hier sind die Klassen:

Set

namespace FranchiseManagerTest.Models 
    { 
     public class Set 
     {   
      [Key] 
      public int SetID { get; set; } 
      public string SetName { get; set; } 
      public string MainAddress { get; set; } 
      public string TimeZone { get; set; }  
      public virtual ICollection<Franchise> Franchises { get; set; } 
     } 
    } 

Franchise

namespace FranchiseManagerTest.Models 
{ 
    public class Franchise 
    { 
     [Key] 
     public int FranchiseID { get; set; }   
     public int SetID { get; set; } 
     public string FranchiseName { get; set; } 
     public string FranchiseNumber { get; set; }  

     public virtual Set Set { get; set; } 

    } 
} 

Dann habe ich einige Test Franchise-Sets und Franchises erstellt.

Hier ist die Hauptansicht:

enter image description here

Das Projekt erfordert, dass alle Franchises zu einem Set sind innerhalb der entsprechenden Set sichtbar bezogen. Außerdem muss ich in der Lage sein, einem Set eine Franchise hinzuzufügen, während ich in den Details des Sets bin.

ich einen Screenshot erstellt zu veranschaulichen, wie es aussieht, nachdem ich „Details“ auf der Hauptansicht klicken:

enter image description here

Der Neue Franchise Knopf mit einer Action erstellt wird, der wie folgt aussieht:

@Html.ActionLink("New Franchise", "Create", "Franchise", null, new { @class = "btn btn-large btn-primary" }) 

Dies bringt mich zum Franchise-Seite erstellen, die wie folgt aussieht:

enter image description here

Das Problem, wie man sehen kann, ist, dass der Drop-Down, die das zugehörige Set Modell enthalten soll, ist nicht bevölkert Vor - stattdessen hat ich die Dropdown-Liste klicken und wählen Sie erneut die Set, das ich bereits bin . in

die Drop-Down-ist bevölkert wird - aber von allen existierenden Sets - anstelle des Set, das ich innerhalb von bin.

Hier ist die Drop-Down ist, wenn ich darauf klicken:

enter image description here

Innerhalb des Franchise Ansicht erstellen, das ist, was das Drop-Down und das Etikett wie folgt aussehen:

 <div class="editor-label"> 
      @Html.LabelFor(model => model.SetID, "Set") 
     </div> 
     <div class="editor-field"> 
      @Html.DropDownList("SetID", String.Empty) 
      @Html.ValidationMessageFor(model => model.SetID) 
     </div> 

Hier ist, was ich versucht habe:


Ich versuchte, in einem setId Wert auf die Ansicht mit dem Actionweitergeben muß:

@Html.ActionLink("New Franchise", "Create", "Franchise", Model.SetID, new { @class = "btn btn-large btn-primary" }) 

ich dann das String.Empty Attribut der Ansicht erstellen, um dies zu ändern versucht:

<div class="editor-label"> 
     @Html.LabelFor(model => model.SetID, "Set") 
    </div> 
    <div class="editor-field"> 
     @Html.DropDownList("SetID", Model.SetID) 
     @Html.ValidationMessageFor(model => model.SetID) 
    </div> 

Dies hat jedoch nicht funktioniert und generiert Ungültige Argument Fehler. Hier

ist ein möglicher Hinweis

Als ich die Franchise-Ansicht aus dem zugehörigen Set erstellen besuchen, die ich in bin, hier ist das, was die URL aussieht (oder ein anderes Thema?):

enter image description here

ich würde davon ausgehen, dass, wenn die Verbände zwischen Set und Franchise korrekt war, und wenn ich eine Franchise in einem Set hinzuzufügen ging, dass die URL Klo würde k wie folgt:

localhost:52987/Set/1/Franchise/Create 

Ist dies eine falsche Annahme zu machen - ist dies in .NET MVC möglich?

Jeder Rat hier wird sehr geschätzt!


EDITS


Hier sind die Routen in meinem Global.asax-Datei, wenn dies nützlich ist:

public static void RegisterRoutes(RouteCollection routes) 
     { 
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

      routes.MapHttpRoute(
       name: "DefaultApi", 
       routeTemplate: "api/{controller}/{id}", 
       defaults: new { id = RouteParameter.Optional } 
      ); 

      routes.MapRoute(
       name: "Default", 
       url: "{controller}/{action}/{id}", 
       defaults: new { controller = "Set", action = "Index", id = UrlParameter.Optional } 
      ); 
     } 

wie gewünscht - hier beide sind die GET und POST Erstellen Sie Methoden des Franchise-Controllers:

// 
    // GET: /Franchise/Create 

    public ActionResult Create() 
    { 
     ViewBag.SetID = new SelectList(db.Sets, "SetID", "SetName"); 
     return View(); 
    } 

    // 
    // POST: /Franchise/Create 

    [HttpPost] 
    public ActionResult Create(Franchise franchise) 
    { 
     if (ModelState.IsValid) 
     { 
      db.Franchises.Add(franchise); 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 

     ViewBag.SetID = new SelectList(db.Sets, "SetID", "SetName", franchise.SetID); 
     return View(franchise); 
    } 

Lassen Sie es mich wissen, wenn mehr Code hilfreich sein wird.

+0

Wie sieht Ihre FranchiseController.Create-Methode aus? – StriplingWarrior

+0

Hey Stripling - Ich habe den Controller-Code zum Bearbeiten-Bereich meines OPs hinzugefügt. Es kann sehr gut etwas mit dem Controller sein - nur nicht sicher was. Ich habe versucht, einen Parameter für SetID in die Methode GET Create zu setzen, aber kein Glück. Nochmal - ich bin mir sicher, ich mache es nur falsch. Ich habe den Parameter entfernt und so sieht es jetzt aus. – PhillipKregg

+1

Sie müssen Ihre Create-Methode so ändern, wie es justinb138 vorschlägt. Es muss einen 'SetID'-Parameter aufnehmen, so dass der von Ihnen übergebene Parameter als Standardwert im Dropdown-Menü verwendet werden kann. (Vielleicht möchten Sie sogar eine versteckte Eingabe für diesen Wert anstelle eines Dropdowns verwenden, es sei denn, Sie erwarten, dass die Leute das Franchise ändern) – StriplingWarrior

Antwort

3

Ich bin ein wenig verwirrt, was Sie zu tun suchen, aber ich würde ein paar Änderungen vorschlagen:

Ich würde dies ändern:

<div class="editor-label"> 
    @Html.LabelFor(model => model.SetID, "Set") 
</div> 
<div class="editor-field"> 
    @Html.DropDownList("SetID", Model.SetID) 
    @Html.ValidationMessageFor(model => model.SetID) 
</div> 

dazu:

<div class="editor-label"> 
    @Html.LabelFor(model => model.SetID, "Set") 
</div> 
<div class="editor-field"> 
    @Html.DropDownListFor(model => model.SetID, (SelectList)ViewBag.FranchiseSets) 
    @Html.ValidationMessageFor(model => model.SetID) 
</div> 

Wenn Sie in dem SetID Wert übergeben, um Ihren ActionMethod erstellen und zuweisen, sollte es pas erhalten sed zur Aussicht. Es sieht so aus, als würden Sie die DropDownList nicht füllen, daher gibt es keine Auswahlmöglichkeit in der Auswahlliste.

public ActionResult Create(int SetID) 
{ 
    ViewBag.FranchiseSets = new SelectList(...); 
    var franchise = new Franchise { SetID = SetID }; 
    return View(franchise); 
} 
+0

Danke für die Hilfe. Es ist im Grunde eine einfache CRUD-App. CRUD-Aktionen müssen für untergeordnete Elemente ausgeführt werden, während sie sich im übergeordneten Element befinden. Die Auswahlliste in der Ansicht "Franchise erstellen" wird tatsächlich von allen vorhandenen Franchise-Sets ausgefüllt. Das Problem ist, dass ich das neue Franchise innerhalb eines Sets erstelle - also sollte Set bereits in der Dropdownliste angezeigt werden, ohne dass der Benutzer auf das Drop-down-Menü klicken und das Set, in dem er sich befindet, erneut auswählen muss. – PhillipKregg

+0

+1, gute Antwort! – StriplingWarrior

+0

Großartig - versuchte dies und es scheint jetzt zu arbeiten. Danke für Ihre Hilfe! – PhillipKregg

1

Es ist unklar, wie genau Ihre Aktionen und Routen eingerichtet sind, aber Sie können dies ausprobieren möchten:

@Html.ActionLink("New Franchise", "Create", "Franchise", new{Model.SetID}, new { @class = "btn btn-large btn-primary" }) 

Durch das Erstellen eines Objekts mit einem SetID Eigenschaft, wird MVC wissen, dass der Parameter sein soll benannte "SetID".

PS - darf ich eine Umbenennung von Set in (FranchiseSet oder FranchiseGroup usw.) vorschlagen, um Kollisionen zu vermeiden? Setis one of the most ambiguous and common words in englischer Sprache.

+0

Danke für die Kommentare - Ich habe gerade versucht mit der neuen {Model.SetId}, aber das hat leider auch nicht funktioniert. Ich werde die Routen in meiner Global.asax-Datei veröffentlichen, wenn Sie möchten - aber sie sind die Standardrouten, die vom Framework erstellt werden. Ich hatte tatsächlich am Anfang zu FranchiseSet benannt - aber wenn die Datenbank erstellt wurde, würde FranchiseSet_ID anstelle von FranchiseSetID erstellen. Ich konnte die Assoziationen nie zur Arbeit bringen, bis ich den Namen änderte. Ich kann stattdessen versuchen, "Franchise-Set" zu verwenden. – PhillipKregg

+0

@PhillipKregg: Bezüglich des Datenbanknamens: Es könnte besser sein, es 'FranchiseSetId' anstelle von' FranchiseSetID' zu nennen. Das Framework denkt wahrscheinlich, dass es den Unterstrich hinzufügen muss, um die Großbuchstaben oder etwas anderes zu unterscheiden. – StriplingWarrior