Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could not find a property named 'xxx.yyy' in FormView (two-way binding for nested properties)

I have this error when I try to update a FormView

Could not find a property named 'MainContact.FirstName' on the type specified by the DataObjectTypeName property in ObjectDataSource 'odsForm'.

I think it is because I use in the EditTemplate a Textbox like this

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

It shows the right text in the Textbox, but apparently it doesn't work when it updates.

This is the datasource of the 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>

This is the EntryItem Class

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

And the Person Class

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

The debugger gets in the FormView ItemUpdating event handler, but never in Helpers.DataAccessers.EntryHelper.UpdateEntry.

How can I solve this?

like image 436
Vinzcent Avatar asked Apr 17 '12 13:04

Vinzcent


1 Answers

You could write your own control able to perform binding as you want, to be used this way (I made one of this):

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

Anyway, I suggest you not to use domain objects directly in pages, and overall not to write them with an ObjectDataSource. The problem is that when you will change your domain for example to add a field:

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

Then you will need to change all the GridViews, FormViews, etc. to store the BirthDate, otherwise the framework will call your ObjectDataSource Update method putting null in the BirthDate. For example:

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

It will read your persons from the database. Each person will have a birth date set. When you save, the person will updated with BirthDate to null, because the GridView does not store the new field.

I think the best solution is to write DTOs for databinding (and leave them in the Presentation Layer) and DataObjects. In your case:

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

In this way any addition to your domain will be safe for your views, and DataObjects will read/write only the fields they need.

like image 122
onof Avatar answered Sep 28 '22 21:09

onof