2012-04-17 18 views
7

Ich habe diesen Fehler, wenn ich versuche, eine Formviewkann nicht eine Eigenschaft namens finden ‚xxx.yyy‘ in Formview (Zwei-Wege für verschachtelte Eigenschaften Bindung)

aktualisieren kann nicht eine Eigenschaft namens ‚gefunden MainContact .FirstName 'vom Typ , der von der DataObjectTypeName-Eigenschaft in ObjectDataSource ' odsForm 'angegeben wird.

Ich denke, es liegt daran, dass ich in der EditTemplate eine Textbox wie diese verwenden

<asp:TextBox Text='<%# Bind("MainContact.FirstName") %>' ID="txtFirstName" runat="server" /> 

Es zeigt den richtigen Text in der Textbox, aber anscheinend ist es nicht funktioniert, wenn es aktualisiert.

Dies ist die Datenquelle des Formview

<asp:ObjectDataSource ID="odsForm" runat="server" DataObjectTypeName="Helpers.BusinessObjects.EntryItem" 
    SelectMethod="GetEntryByEmail" TypeName="Helpers.DataAccessers.EntryHelper" 
    UpdateMethod="UpdateEntry"> 
    <SelectParameters> 
     <asp:SessionParameter SessionField="email" Name="email" Type="String" /> 
    </SelectParameters> 
</asp:ObjectDataSource> 

Dies ist die EntryItem Klasse

public class EntryItem 
    { 
     public int Id { get; set; } 
     public string Email { get; set; } 
     public string Password { get; set; } 
     public Person MainContact { get; set; } 
     ... 
    } 

und die Person Klasse

public class Person 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    ... 
} 

Der Debugger im Ereignishandler Formview ItemUpdating bekommt , aber niemals in .

Wie kann ich das lösen?

Antwort

1

Zwei mögliche Ansätze.

Zuerst können Sie DataObjectTypeName="Helpers.BusinessObjects.EntryItem" aus der Definition Ihres ObjectDataSource fallen lassen. Ich habe das NIE benutzt und Bindungen funktionieren immer.

Aber das wird wahrscheinlich nicht helfen, wie die Bind/Eval ist wahrscheinlich nicht in der Lage, Referenzen zu folgen (Bind("MainContact.FirstName")).

dieser Stattdessen umschreiben als

<%# ((EntryItem)Container.DataItem).MainContract.FirstName #> 

Der Nachteil ist, dass man locker automatische Zwei-Wege-Bindung, so dass Sie das Bindemittel ein wenig helfen. Fügen Sie einfach einen Inserting/Updating Handler Ihre Object und innerhalb Handler:

protected void TheObjectDataSource_Updating(object sender, BlahBlahEventArgs e) 
{ 
    // find the control in the data bound parent 
    TextBox txt = (TextBox)YourFormView.FindControl("txtFirstName"); 

    // read the value and add it to parameters 
    e.Parameters.Add("nameofyourparameter", txt.Text); 
} 
0

Nach ein paar Quellen, es eigentlich nicht möglich ist, zwei-Wege mit verschachtelten Eigenschaften Bindung zu tun.

Hier ist eine Antwort auf eine ähnliche Frage hier auf SO: https://stackoverflow.com/a/1195119/370671.

Auch there's a blog post beschreibt das Problem:

nun noch in den meisten Fällen ObjectDataSource verwendet werden Sie keine Probleme verursachen, wenn was [Sie] bind eine einfache Eigenschaft wie Name eines Client also ist: Sie haben eine Sammlung von Clients, die Sie an eine GridView binden, und eine der Spalten zeigt den Namen des Clients an. Dazu verwenden Sie etwas wie 10. Das Problem tritt auf, wenn Sie eine Bindung an eine Untereigenschaft wie in Bind("Address.StreetName") herstellen müssen.Das wird nicht funktionieren

4

Sie können Ihre eigene Steuer schreiben könnte Bindung auszuführen, wie Sie wollen, auf diese Art und Weise verwendet werden (ich habe daraus gemacht):

<ItemTemplate> 
     <%# Eval("MainContact.FirstName")%> 
    </ItemTemplate> 
    <EditItemTemplate> 
     <xx:BinderHelper runat="server" DataSource='<%# Bind("MainContact") %>'> 
     <ItemTemplate> 
      <asp:TextBox Text='<%# Bind("FirstName") %>' ID="txtFirstName" 
      runat="server" /> 
     </ItemTemplate> 
     </xx:BinderHelper> 
    </EditItemTemplate> 

Wie auch immer, ich schlage vor, Sie Domänenobjekte nicht direkt in Seiten zu verwenden und insgesamt nicht mit einer ObjectDataSource zu schreiben. Das Problem ist, dass, wenn Sie Ihre Domain ändern wird zum Beispiel ein Feld hinzufügen:

public class Person 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 

    // just added 
    public DateTime? BirthDate { get; set; } 
} 

Dann müssen Sie alle Gridviews ändern, FormViews usw. das Geburtsdatum zu speichern, da sonst der Rahmen rufen Ihre Object Update Methode Put null im Geburtsdatum. Zum Beispiel:

<asp:GridView runat="server" DataSourceID="odsForm" AutoGenerateColumns="False"> 
    <Columns> 
     <asp:CommandField runat="server" ShowEditButton="True" /> 
     <asp:BoundField DataField="FirstName" /> 
     <asp:BoundField DataField="LastName" /> 
</Columns> 
    </asp:GridView> 

Es liest Ihre Personen aus der Datenbank. Für jede Person wird ein Geburtsdatum festgelegt. Wenn Sie speichern, wird die Person mit BirthDate zu null aktualisiert, da das GridView das neue Feld nicht speichert.

Ich denke, die beste Lösung besteht darin, DTOs für Databinding (und lassen Sie sie in der Präsentationsebene) und DataObjects schreiben. In Ihrem Fall:

public class EntryItemView 
{ 
    public int Id { get; set; } 
    public string Email { get; set; } 
    public string Password { get; set; } 
    public string MainContactFirstName { get; set; } 
} 

[DataObject] 
public class EntryItemViewDataObject { 
    [DataObjectMethod(DataObjectMethodType.Select)] 
    public EntryItemView GetItem(...) { 
     // TODO: read from the database, convert to DTO 
    } 

    [DataObjectMethod(DataObjectMethodType.Update)] 
    public void Update(EntryItemView entry) { 

     EntryItem domainObject = getById(entry.Id); 
     // TODO: use EmitMapper or AutoMapper 
     domainObject.MainContact.FirstName = entry.MainContactFirstName; 

     // TODO: save 
    } 
} 

Auf diese Weise jede zusätzlich zu Ihrer Domain für Ihre Ansichten sicher sein, und Datenobjekte wird lesen/schreiben nur die Felder, die sie benötigen.

+0

+1: Ich verbrenne immer meine Zeit verschwenden mit der 'ObjectDataSource' Ich hoffe nur, das nächste Mal erinnere ich mich nicht mit ihnen zu belästigen. – capdragon