2012-04-17 13 views
7

Tôi có lỗi này khi tôi cố gắng cập nhật một FormViewkhông thể tìm thấy một tài sản có tên là 'xxx.yyy' trong FormView (hai chiều ràng buộc đối với tài sản lồng nhau)

không thể tìm thấy một tài sản có tên là 'MainContact .FirstName 'trên loại được chỉ định bởi thuộc tính DataObjectTypeName trong ObjectDataSource ' odsForm '.

Tôi nghĩ rằng đó là vì tôi sử dụng trong các EditTemplate một Textbox như thế này

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

Nó cho thấy văn bản ngay trong Textbox, nhưng dường như nó không hoạt động khi nó cập nhật.

Đây là nguồn dữ liệu của 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> 

Đây là EntryItem Lớp

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

Và Lớp Person

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

Các debugger được trong xử lý sự kiện FormView ItemUpdating , nhưng không bao giờ ở số Helpers.DataAccessers.EntryHelper.UpdateEntry.

Tôi làm cách nào để giải quyết vấn đề này?

Trả lời

1

Hai phương pháp có thể có.

Trước tiên, bạn có thể thả DataObjectTypeName="Helpers.BusinessObjects.EntryItem" từ định nghĩa của ObjectDataSource. Tôi KHÔNG BAO GIỜ sử dụng nó và các ràng buộc luôn hoạt động.

Nhưng điều này có thể không hữu ích, vì Bind/Eval có thể không thể theo dõi các tham chiếu (Bind("MainContact.FirstName")).

Thay vào đó, viết lại này như

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

Nhược điểm là bạn lỏng tự động hai chiều ràng buộc, do đó bạn phải giúp các chất kết dính một chút. Chỉ cần thêm một Inserting/Updating xử lý để ObjectDataSource của bạn và bên trong bộ xử lý:

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

Theo một vài nguồn tin, nó thực sự không thể làm hai chiều gắn với tính chất lồng nhau.

Đây là một câu trả lời cho một câu hỏi tương tự ở đây trên SO: https://stackoverflow.com/a/1195119/370671.

Ngoài ra, there's a blog post mô tả vấn đề:

Bây giờ, vẫn còn trong hầu hết các trường hợp sử dụng ObjectDataSource sẽ không gây cho bạn bất kỳ vấn đề khi những gì [you] ràng buộc là một tài sản đơn giản như tên của một ví dụ khách hàng: bạn có một bộ sưu tập các khách hàng mà bạn liên kết với một GridView và một trong các cột hiển thị tên của khách hàng. Để làm như vậy, bạn sử dụng một cái gì đó như Bind("Name"). Vấn đề phát sinh khi bạn cần phải liên kết với một subproperty như trong Bind("Address.StreetName").Điều này sẽ không làm việc

4

Bạn có thể viết kiểm soát của riêng bạn có thể thực hiện ràng buộc như bạn muốn, để được sử dụng theo cách này (tôi đã thực hiện một trong những điều này):

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

Dù sao, tôi đề nghị bạn không sử dụng các đối tượng miền trực tiếp trong các trang, và tổng thể không viết chúng với một ObjectDataSource. Vấn đề là khi bạn sẽ thay đổi tên miền của bạn ví dụ để thêm một lĩnh vực:

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

Sau đó, bạn sẽ cần phải thay đổi tất cả các GridViews, FormViews, vv để lưu trữ các sinh, nếu không khuôn khổ sẽ gọi ObjectDataSource của bạn Phương thức cập nhật đặt null vào ngày sinh. Ví dụ:

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

Nó sẽ đọc người của bạn từ cơ sở dữ liệu. Mỗi người sẽ có ngày sinh. Khi bạn lưu, người đó sẽ cập nhật Ngày sinh thành null, vì GridView không lưu trữ trường mới.

Tôi nghĩ giải pháp tốt nhất là viết DTO cho databinding (và để chúng trong lớp trình bày) và DataObjects. Trong trường hợp của bạn:

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

Bằng cách này, mọi bổ sung cho miền của bạn sẽ an toàn cho chế độ xem của bạn và DataObject sẽ chỉ đọc/ghi các trường họ cần.

+0

+1: Tôi luôn bị đốt cháy lãng phí thời gian của mình với 'ObjectDataSource' Tôi chỉ hy vọng lần sau tôi nhớ không bận tâm với họ. – capdragon