7

当我尝试更新 FormView 时出现此错误

在 ObjectDataSource“odsForm”中的 DataObjectTypeName 属性指定的类型上找不到名为“MainContact.FirstName”的属性。

我认为这是因为我在 EditTemplate 中使用了这样的文本框

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

它在文本框中显示正确的文本,但显然它在更新时不起作用。

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

这是 EntryItem 类

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

和 Person 类

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

调试器进入 FormViewItemUpdating事件处理程序,但永远不会进入Helpers.DataAccessers.EntryHelper.UpdateEntry.

我该如何解决这个问题?

4

3 回答 3

4

您可以编写自己的控件,能够根据需要执行绑定,以这种方式使用(我做了一个):

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

无论如何,我建议您不要直接在页面中使用域对象,并且总体上不要使用 ObjectDataSource 编写它们。问题是,当您更改域时,例如添加一个字段:

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

然后您将需要更改所有 GridViews、FormViews 等以存储 BirthDate,否则框架将调用您的 ObjectDataSource Update 方法放入nullBirthDate。例如:

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

它将从数据库中读取您的人员。每个人都会有一个出生日期。保存时,此人将使用 BirthDate 更新为null,因为 GridView 不存储新字段。

我认为最好的解决方案是为数据绑定(并将它们留在表示层)和 DataObjects 编写 DTO。在你的情况下:

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

这样,对您的域的任何添加对您的视图都是安全的,并且 DataObjects 将仅读取/写入它们需要的字段。

于 2012-08-24T07:10:47.807 回答
1

两种可能的方法。

首先,您可以DataObjectTypeName="Helpers.BusinessObjects.EntryItem"从您的ObjectDataSource. 我从来没有使用过,绑定总是有效的。

但这可能无济于事,因为Bind/Eval可能无法遵循参考 ( Bind("MainContact.FirstName"))。

相反,将其重写为

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

缺点是您松开了自动双向绑定,因此您必须稍微帮助粘合剂。只需将Inserting/Updating处理程序添加到您的 ObjectDataSource 和内部处理程序:

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 );
}
于 2012-08-21T18:25:40.573 回答
0

根据一些消息来源,实际上不可能使用嵌套属性进行双向绑定。

这是对 SO 上类似问题的一个答案:https ://stackoverflow.com/a/1195119/370671 。

此外,还有一篇博客文章描述了这个问题:

现在,在大多数情况下,ObjectDataSource当 [您] 绑定的是一个简单属性(例如客户端名称)时,使用仍然不会给您带来任何问题,即:您有一个绑定到 a 的客户端集合,GridView其中一个列显示客户的名称。为此,您使用类似Bind("Name"). 当您需要绑定到诸如 in 之类的子属性时,就会出现问题 Bind("Address.StreetName")。这行不通

于 2012-08-21T18:38:26.357 回答