在 FormView 中找不到名为“xxx.yyy”的属性(嵌套属性的双向绑定)
本文关键字:属性 嵌套 绑定 yyy 找不到 FormView xxx | 更新日期: 2023-09-27 18:31:27
当我尝试更新 FormView 时遇到此错误
在类型上找不到名为"MainContact.FirstName"的属性 由对象数据源中的 DataObjectTypeName 属性指定 "odsForm"。
我认为这是因为我在编辑模板中使用了这样的文本框
<asp:TextBox Text='<%# Bind("MainContact.FirstName") %>' ID="txtFirstName" runat="server" />
它在文本框中显示正确的文本,但显然它在更新时不起作用。
这是窗体视图的数据源
<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>
这是条目项类
public class EntryItem
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public Person MainContact { get; set; }
...
}
和人类
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
调试器进入 FormView ItemUpdating
事件处理程序,但永远不会进入Helpers.DataAccessers.EntryHelper.UpdateEntry
。
我该如何解决这个问题?
您可以编写自己的控件,以便根据需要执行绑定,以这种方式使用(我制作了其中之一):
<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、FormView 等来存储 BirthDate,否则框架将调用 ObjectDataSource Update 方法,将null
放入 BirthDate 中。例如:
<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>
它将从数据库中读取您的人员。每个人都会设定一个出生日期。保存时,此人将使用"出生日期"更新为 null
,因为 GridView 不存储新字段。
我认为最好的解决方案是为数据绑定编写 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 将仅读取/写入它们所需的字段。
两种可能的方法。
首先,您可以从ObjectDataSource
的定义中删除DataObjectTypeName="Helpers.BusinessObjects.EntryItem"
。我从来没有用过它,绑定总是有效的。
但这可能不会有所帮助,因为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 );
}
根据几个来源,实际上不可能对嵌套属性进行双向绑定。
以下是SO上类似问题的一个答案:https://stackoverflow.com/a/1195119/370671。
此外,还有一篇描述该问题的博客文章:
现在,在大多数情况下,当 [you] 绑定的是一个简单的属性(例如客户端的名称)时,仍然使用
ObjectDataSource
不会给您带来任何问题,即:您有一个绑定到GridView
的客户端集合,其中一列显示客户端的名称。为此,您可以使用类似Bind("Name")
.当您需要绑定到子属性(例如Bind("Address.StreetName")
.这行不通