2009-05-20 22 views
8

Ich habe eine ASP.Net MVC-Anwendung mit einem Modell, das mehrere Schichten tief ist, die eine Sammlung enthält.ASP.Net MVC - Modell mit Sammlung nicht auf Postback Population

Ich glaube, dass die Ansicht zum Erstellen der Objekte alle richtig eingerichtet ist, aber es füllt nur nicht die Auflistung innerhalb des Modells, wenn ich das Formular an den Server senden.

Ich habe ein Stück von Daten, die somit in der Klassenhierarchie zu finden ist:

person.PersonDetails.ContactInformation[0].Data; 

Diese Klassenstruktur von LinqToSQL erstellt wird, und ist vom Typ Contact EntitySet<ContactData>. Zum Erstellen der Ansicht ich folgend passieren:

return View(person); 

und in der Ansicht, habe ich eine Form, die ein einziges Textfeld mit dem Namen des oben genannten Bereich zugeordnet enthält:

<%= Html.TextBox("person.PersonDetails.ContactInformation[0].Data")%> 

die POST-Methode in meinem Controller dann ist wie folgt:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create (Person person) 
{ 
    //Do stuff to validate and add to the database 
} 

Es ist an dieser Stelle, wo ich als person.PersonDetails.ContactInformation.Count() == 0 verloren gehen. Also der ModelBinder hat ein ContactInformation Objekt erstellt, aber nicht mit dem Objekt gefüllt, das es halten sollte (zB ContactData) mit dem Index 0.

Meine Frage ist zweifach: 1. Habe ich den richtigen Ansatz genommen .. dh sollte diese Arbeit? 2. Irgendwelche Ideen, warum es das ContactInformation-Objekt möglicherweise nicht füllen konnte?

Vielen Dank, Richard

Antwort

20

Ich denke, dass Ihr Modell für das Standardmodell Bindemittel zu komplex ist, um damit zu arbeiten. Sie könnten versuchen, mehrere Parameter verwenden und sie binden mit Präfixen:

public ActionResult Create( 
    Person person, 
    [Bind(Prefix="Person.PersonDetails")] 
    PersonDetails details, 
    [Bind(Prefix="Person.PersonDetails.ContactInformation")] 
    ContactInformation[] info) 
{ 
     person.PersonDetails = details; 
     person.PersonDetails.ContactInformation = info; 

     ... 
} 

Oder Sie könnten Ihr eigenes Modell Bindemittel zu entwickeln, würde verstehen, wie Ihr komplexes Modell aus den Formulareingaben abzuleiten.

+1

Danke, das funktioniert perfekt. Ich habe ein Beispiel mit viel tieferer Hierarchie versucht, das sehr gut funktioniert hat, aber Sie haben wahrscheinlich Recht, dass es sich in der Komplexität verliert. Zwei Kommentare zur Verdeutlichung: 1. Ich brauchte nur die [Bind (Prefix = "Person.PersonDetails.ContactInformation")] ContactInformation [] info) und entsprechende Einstellung des Modellobjekts. 2. ContactInformation [] muss EntitySet entsprechen, damit sie dem richtigen Typ entspricht. Jetzt, um mehr Details über Präfix nachzuschlagen .... Danke für Ihre Hilfe. Richard – Richbits

+0

Schön, hatte noch nicht über "Präfixe" gelesen! – Ropstah

+0

gute .. Oder Sie könnten Ihre eigenen benutzerdefinierten Modellbinder entwickeln, die verstehen würde, wie Sie Ihr komplexes Modell aus den Formulareingaben ableiten, können Sie Link oder impl teilen. Wenn du es schon getan hast? –

0

Vielleicht Mangel an Bind-Attribute ist der Fall:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create ([Bind] Person person) 
{ 
// Do stuff to validate and add to the database 
} 
+0

Danke, ich habe dies einen Versuch ohne Glück gegeben. Die Tatsache, dass es für die Person bindend ist und Objekte bis zum ContactInformation-Objekt erzeugt, weist darauf hin, dass es bindend ist, nur nicht auf die ContactData-Ebene. – Richbits

+0

Nein, Bind ist nur für ein Argument erforderlich, wenn Sie die Standardbindungsregeln ändern müssen. –

0

Das erste Argument von Html.TextBox ist der Name der Textbox, würde der zweite der Wert sein.

"Wrong":

<%= Html.TextBox("person.PersonDetails.ContactInformation[0].Data")%> 

"Recht":

<%= Html.TextBox("nameoftextbox", person.PersonDetails.ContactInformation[0].Data)%> 
+2

Danke, aber mein Verständnis ist, dass der zweite Parameter der Wert ist, der verwendet wird, um das Textfeld in einem z. Bearbeitungsszenario. Der erste Wert wird vom defaultmodelbinder verwendet, um das Formular an ein Objekt zu binden, das beim Zurücksetzen erstellt wurde. – Richbits

+0

Mein schlechtes ........... – Ropstah

5

Wenn eine Eigenschaft null ist, konnte der Modellbinder other ihn nicht finden oder konnte keine Werte im übermittelten Formular finden, die erforderlich sind, um eine Instanz des Typs der Eigenschaft zu erstellen. Wenn die Eigenschaft beispielsweise eine nicht nullfähige ID hat und Ihr Formular keine Daten für diese ID enthält, wird die Eigenschaft vom Modellbinder als null belassen, da keine neue Instanz des Typs erstellt werden kann, ohne die ID zu kennen.Um dieses Problem zu diagnostizieren, müssen Sie die Daten im übermittelten Formular (das ist bei Firebug oder Fiddler leicht zu sehen) mit der Struktur des Objekts vergleichen, das Sie erwarten, dass der Modellbinder gefüllt wird. Wenn erforderliche Felder fehlen oder wenn die Werte so übergeben werden, dass sie nicht in den Typ eines erforderlichen Felds konvertiert werden können, wird das gesamte Objekt auf Null gesetzt.

+2

Das klingt richtig. –

+0

Danke, sicher, wenn das, was Sie hier sagen, korrekt ist, dann würde die Lösung von Tvafossen auch scheitern? – Richbits

+0

Nicht unbedingt.Ich beschreibe ein mögliches Problem. Er beschreibt ein anderes. –

1

Ich habe mit dieser gleichen Art von Szenario zu kämpfen und kam schließlich zu erkennen, dass das zugrunde liegende Problem besteht darin, dass der MVC-Standardbinder Modells nicht auf EntitySet <T> Felder zu funktionieren scheint, nur Liste <T> Felder aus. Ich habe jedoch eine einfache Problemumgehung gefunden, die akzeptabel scheint. In meinem Fall habe ich eine Entität "Firma", die eine Beziehung mit "Kontakte" hat (mein Linq-zu-Sql EntitySet).

Da es scheint, dass, wenn ich meinen Code von EntitySet <Kontakt> ändere <Kontakt>, der MVC-Standard-Modell Binder zur Liste beginnt wie erwartet funktioniert (obwohl die LTS jetzt nicht ist), dachte ich, ich würde ein liefern Alternative, "Alias" -Eigenschaft zu MVC, die vom Typ ist Liste <Kontakt>, und tatsächlich scheint dies zu funktionieren.

In meiner Firma Entitätsklasse:


// This is what LINQ-to-SQL will use: 
private EntitySet<Contact> _Contacts = new EntitySet<Contact>(); 
[Association(Storage="_Contacts", OtherKey="CompanyID", ThisKey="ID")] 
public EntitySet<Contact> Contacts 
{ 
    get { return _Contacts; } 
    set { _Contacts.Assign(value); } 
} 

// This is what MVC default model binder (and my View) will use: 
public List<Contact> MvcContacts 
{ 
    get { return _Contacts.ToList<Contact>(); } 
    set { _Contacts.AddRange(value); } 
} 

So, jetzt, in meiner Ansicht, ich habe folgende:

 
<label>First Name* 
    <%= Html.TextBox("Company.MvcContacts[" + i + "].FirstName") %> 
</label> 
<label>Last Name* 
    <%= Html.TextBox("Company.MvcContacts[" + i + "].LastName") %> 
</label> 

Scheint wie ein Zauber zu arbeiten!

Viel Glück! -Mike

+0

Danke, es tut mir leid für eine Weile weg. Ich hoffe, dass Sie die Antwort auf MSDN gesehen haben (ich nehme an, dass Sie es waren, der dort kommentierte). Ich habe auch einen Fehler auf der Verbindungsseite protokolliert, und es wurde bestätigt, dass dies in .Net 4.0 behoben wurde. In meinem Fall denke ich, dass Ihre Lösung zu kompliziert wird, da der Entitätssatz tief in meiner Klassenstruktur liegt. Ich habe auch festgestellt, dass das Bearbeiten von EntitySets ein echtes Problem ist, da eine neue Datenbankzeile erstellt wird und nicht aktualisiert wird. Hoffentlich wird dies auch für 4.0 aussortiert. – Richbits

+0

Es ist schön zu hören, dass dies angesprochen wird. Und ja, ich habe die selbe Lösung praktisch zur gleichen Zeit bei der Microsoft Newsgroup gepostet: Ich wusste bis jetzt nicht, dass du derjenige warst, der es angefangen hat! Sie haben eine Antwort von Allen bekommen, die zeigt, wie man den Property-Setter repariert, der idealer erscheint, aber in meinem Fall benutze ich LTS-generierte Entitäten und bin mir nicht sicher, wie ich das einfach beheben kann (ohne natürlich größere Workarounds). P.S., der andere Thread ist hier: http://groups.google.com/group/microsoft.public.dotnet.framework.aspnet/browse_thread/thread/a2869970f33c712a/188c0a9e5c00dc2a – Funka

0

Stellen Sie sicher, dass Ihre Modelle (und alle geschachtelten Modelle) Eigenschaften (Getter/Setter) anstelle von Feldern verwenden. Anscheinend benötigt der Standardordner Eigenschaften, um ordnungsgemäß zu funktionieren. Ich hatte eine sehr ähnliche Situation, die behoben wurde, indem die erforderlichen Felder in Eigenschaften geändert wurden.

Verwandte Themen