CodeSmith Community
Your Code. Your Way. Faster!

Using the ManyToManyViewRelationship Control

Latest post 08-11-2008 1:40 AM by Xcalibur. 30 replies.
  • 04-23-2006 9:54 PM

    • bdiaz
    • Top 10 Contributor
    • Joined on 02-20-2006
    • Houston, TX
    • Posts 504
    • Points 15,290

    Using the ManyToManyViewRelationship Control

    In this thread, I will demonstrate the use of the ManyToManyViewRelationship control as a declarative approach to managing complex many-to-many relationships.  This example comes straight out of a project that I am currently working on; one which continues to be the motivation behind all of the classes in the Web Library.  I hope that others will benefit from this and every sample that I post, but if any clarification is needed, questions and/or comments are always welcome!

    Regards,
    Bobby


    Bobby Diaz ------------------------------------------ Member of the .NetTiers team http://www.nettiers.com ------------------------------------------
    • Post Points: 135
  • 04-23-2006 9:55 PM In reply to

    • bdiaz
    • Top 10 Contributor
    • Joined on 02-20-2006
    • Houston, TX
    • Posts 504
    • Points 15,290

    Re: Using the ManyToManyViewRelationship Control

    First, a screenshot:



    Bobby Diaz ------------------------------------------ Member of the .NetTiers team http://www.nettiers.com ------------------------------------------
    • Post Points: 35
  • 04-23-2006 10:02 PM In reply to

    • bdiaz
    • Top 10 Contributor
    • Joined on 02-20-2006
    • Houston, TX
    • Posts 504
    • Points 15,290

    Re: Using the ManyToManyViewRelationship Control

    The tab control shown resides in a master page that I called Person.master.  This is also where I placed the main data source control that is used by each of the content pages.

    <phdb:EntityDataSource ID="PersonDataSource" runat="server"
       ProviderName="PersonProvider"
       EntityTypeName="PhDb.BLL.Person, PhDb.BLL"
       EntityKeyName="PersonId"
       SelectMethod="GetByPersonId">
       <Parameters>
          <asp:SessionParameter Name="EntityId" SessionField="PersonId" Type="Object" />
       </Parameters>
    </phdb:EntityDataSource>

    Notice the use of the SessionParameter object that retrieves the previously stored PersonId value.  Some may prefer to pass the identifier value on the url and therefore would use a QueryStringParameter object instead.

    This is a simplified version of the data model I am using for this example:

    Person ( PersonId PK, FirstName, LastName, ... )
    PersonAddress ( PersonId PK, AddressId PK )
    Address ( AddressId PK, Title, Address1, Address2, ... )
    AddressRole ( AddressRoleId PK, RoleName, ... )
    AddressAddressRole ( AddressId PK, AddressRoleId PK )


    Bobby Diaz ------------------------------------------ Member of the .NetTiers team http://www.nettiers.com ------------------------------------------
    • Post Points: 5
  • 04-23-2006 10:47 PM In reply to

    • bdiaz
    • Top 10 Contributor
    • Joined on 02-20-2006
    • Houston, TX
    • Posts 504
    • Points 15,290

    Re: Using the ManyToManyViewRelationship Control

    This is where it gets a little complicated.  I am using nested [Multi]FormView controls to display the address and related data, and a ManyToManyViewRelationship control to manage the linked updates between multiple data sources.

    <asp:FormView ID="EditFormView" runat="server" DataSourceID="PersonDataSource" Width="100%">
    <
    EditItemTemplate>

    <
    asp:Button ID="TopUpdateButton" runat="server" Text="Update" CommandName="Update" />
    <asp:Button ID="TopCancelButton" runat="server" Text="Cancel" CommandName="Cancel" />
    <input type="button" value="Add New" onclick="location.href='Address.aspx?add=1'" />

    <
    asp:GridView ID="AddressGridView" runat="server" DataSourceID="AddressDataSource" Width="100%"
       AutoGenerateColumns="false" ShowHeader="false" BorderWidth="0" BorderColor="#ffffff">
       <Columns>
          <asp:TemplateField>
          <ItemTemplate>

             <hr />
             <phdb:MultiFormView ID="AddressFormView" runat="server"
                
    DataSourceID="AddressDataSource" DataKeyNames="AddressId" DefaultMode="Edit"
                PageIndex='<%# DataBinder.Eval(Container, "RowIndex") %>'>
                <EditItemTemplatePaths>
                   <phdb:TemplatePath Path="~/Address/EditFields.ascx" />
                </EditItemTemplatePaths>
             </phdb:MultiFormView>

             <
    phdb:ManyToManyViewRelationship ID="PersonAddressRelationship" runat="server">
                <PrimaryMember runat="server"
                   DataSourceID="PersonDataSource"
                   EntityKeyName="PersonId" />
                <LinkMember runat="server"
                   
    DataSourceID="PersonAddressDataSource"
                   
    EntityKeyName="PersonId"
                   ForeignKeyName="AddressId" />
                <ReferenceMember runat="server"
                   DataSourceID="AddressDataSource"
                   
    ViewControlID="AddressFormView"
                   EntityKeyName="AddressId" />
             </phdb:ManyToManyViewRelationship>

          </ItemTemplate>
          </asp:TemplateField>
       </Columns>
    </asp:GridView>

    <hr />
    <asp:Button ID="UpdateButton" runat="server" Text="Update" CommandName="Update" />
    <asp:Button ID="CancelButton" runat="server" Text="Cancel" CommandName="Cancel" />
    <input type="button" value="Add New" onclick="location.href='Address.aspx?add=1'" />

    </
    EditItemTemplate>
    </
    asp:FormView>

    <
    phdb:EntityDataSource ID="AddressDataSource" runat="server"
       ProviderName="AddressProvider"
       EntityTypeName="PhDb.BLL.Address, PhDb.BLL"
       EntityKeyName="AddressId"
       SelectMethod="GetByPersonIdFromPersonAddress"
       Sort="IsPrimary DESC, Active DESC, Title">
       <Parameters>
          <asp:SessionParameter Name="EntityId" SessionField="PersonId" Type="Object" />
       </Parameters>
    </phdb:EntityDataSource>

    <
    phdb:EntityDataSource ID="PersonAddressDataSource" runat="server"
       ProviderName="PersonAddressProvider"
       EntityTypeName="PhDb.BLL.PersonAddress, PhDb.BLL"
       EntityKeyName="PersonId"
       SelectMethod="GetByPersonId">
       <Parameters>
          <asp:SessionParameter Name="EntityId" SessionField="PersonId" Type="Object" />
       </Parameters>
    </phdb:EntityDataSource>

    <
    phdb:EntityDataSource ID="AddressRoleDataSource" runat="server"
       ProviderName="AddressRoleProvider"
       EntityTypeName="PhDb.BLL.AddressRole, PhDb.BLL"
       SelectMethod="GetAll"
       Filter="Active = True"
       Sort="RoleName ASC" />

    <
    phdb:EntityDataSource ID="FacilityDataSource" runat="server"
       ProviderName="FacilityProvider"
       EntityTypeName="PhDb.BLL.Facility, PhDb.BLL"
       SelectMethod="GetAll"
       Filter="Active = True"
       Sort="DisplayOrder" />

    <
    phdb:EntityDataSource ID="PhoneDataSource" runat="server"
       ProviderName="PhoneProvider"
       EntityTypeName="PhDb.BLL.Phone, PhDb.BLL"
       SelectMethod="GetByPersonIdFromPersonPhone"
       Filter="Active = True">
       <Parameters>
          <asp:SessionParameter name="EntityId" SessionField="PersonId" Type="Object" />
       </Parameters>
    </phdb:EntityDataSource>


    Bobby Diaz ------------------------------------------ Member of the .NetTiers team http://www.nettiers.com ------------------------------------------
    • Post Points: 90
  • 04-23-2006 11:05 PM In reply to

    • bdiaz
    • Top 10 Contributor
    • Joined on 02-20-2006
    • Houston, TX
    • Posts 504
    • Points 15,290

    Re: Using the ManyToManyViewRelationship Control

    I use the MultiFormView control to separate the code into smaller, more manageable fragments.  In this case, I placed the Address input controls that are loaded into the AddressFormView's EditItemTemplate property in a user control called ~/Address/EditFields.ascx.  Here are the contents of that file:

    <%@ Control Language="C#" ClassName="EditFields" %>

    <
    asp:FormView ID="FormView1" runat="server">
    <
    ItemTemplate>

    <asp:Label ID="AddressIdLabel" runat="server" Text='<%# Bind("AddressId") %>' Visible="false" />

    <
    table border="0" cellpadding="0" cellspacing="0">
    <tr valign="top">
       <td>
          <table class="formTable" border="0">
          <tr>
             <td>Title:</td>
             <td colspan="5"><asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>' /></td>
          </tr>
          <tr>
             <td>Address:</td>
             <td colspan="5"><asp:TextBox ID="Address1TextBox" runat="server" Text='<%# Bind("Address1") %>' /></td>
          </tr>
          <tr>
             <td></td>
             <td colspan="5"><asp:TextBox ID="Address2TextBox" runat="server" Text='<%# Bind("Address2") %>' /></td>
             <td><input type="button" id="btnMore<%# DataBinder.Eval(Container, "PageIndex") %>" value="more..." /></td>
          </tr>
          <tr id="Address3Row<%# DataBinder.Eval(Container, "PageIndex") %>" style="display:none;">
             <td></td>
             <td colspan="5"><asp:TextBox ID="Address3TextBox" runat="server" Text='<%# Bind("Address3") %>' /></td>
          </tr>
          <tr id="Address4Row<%# DataBinder.Eval(Container, "PageIndex") %>" style="display:none;">
             <td></td>
             <td colspan="5"><asp:TextBox ID="Address4TextBox" runat="server" Text='<%# Bind("Address4") %>' /></td>
          </tr>
          <tr>
             <td>City:</td>
             <td><asp:TextBox ID="CityTextBox" runat="server" Text='<%# Bind("City") %>'/></td>
             <td>State:</td>
             <td><asp:TextBox ID="StateTextBox" runat="server" Text='<%# Bind("State") %>' Width="40"/></td>
             <td>Zip:</td>
             <td><asp:TextBox ID="ZipTextBox" runat="server" Text='<%# Bind("Zip") %>' Width="60"/></td>
          </tr>
          <tr>
             <td>County:</td>
             <td><asp:TextBox ID="CountyTextBox" runat="server" Text='<%# Bind("County") %>'/></td>
             <td colspan="2">Is Primary?</td>
             <td colspan="2">
                <asp:DropDownList ID="IsPrimaryList" SelectedValue='<%# Bind("IsPrimary") %>' runat="server">
                   <asp:ListItem Text="Yes" Value="True" />
                   <asp:ListItem Text="No" Value="False" />
                </asp:DropDownList>
             </td>
          </tr>
          <tr>
             <td>Active:</td>
             <td>
                <asp:DropDownList ID="IsActiveList" SelectedValue='<%# Bind("Active") %>' runat="server">
                   <asp:ListItem Text="Yes" Value="True" />
                   <asp:ListItem Text="No" Value="False" />
                   </asp:DropDownList>
                </td>
          </tr>
          </table>
       </td>
       <td style="width:10px;">&nbsp;</td>
       <td nowrap>
          <div><b>Roles:</b></div>

          <
    asp:CheckBoxList ID="AddressRoleList" runat="server"
             DataSourceID="AddressRoleDataSource"
             DataTextField="RoleName"
             DataValueField="AddressRoleId" />

          <
    phdb:EntityDataSource ID="AddressAddressRoleDataSource" runat="server"
             ProviderName="AddressAddressRoleProvider"
             EntityTypeName="PhDb.BLL.AddressAddressRole, PhDb.BLL"
             SelectMethod="GetByAddressId">
             <Parameters>
                <asp:ControlParameter name="EntityId" ControlID="AddressIdLabel" />
             </Parameters>
          </phdb:EntityDataSource>

          <
    phdb:ManyToManyListRelationship ID="AddressAddressRoleRelationship" runat="server">
             <PrimaryMember runat="server"
                DataSourceID="AddressDataSource"
                EntityKeyName="AddressId"
                EntityIndex='<%# DataBinder.Eval(Container, "PageIndex") %>' />
             <LinkMember runat="server"
                DataSourceID="AddressAddressRoleDataSource"
                EntityKeyName="AddressId"
                ForeignKeyName="AddressRoleId" />
             <ReferenceMember runat="server"
                DataSourceID="AddressRoleDataSource"
                ListControlID="AddressRoleList"
                EntityKeyName="AddressRoleId"
                EntityIndex='<%# DataBinder.Eval(Container, "PageIndex") %>' />
          </phdb:ManyToManyListRelationship>
       </td>
       <td style="width:10px;">&nbsp;</td>
       <td nowrap>
          <div><b>Phone Numbers:</b></div>

          <
    asp:CheckBoxList ID="PhoneList" runat="server"
             DataSourceID="PhoneDataSource"
             DataTextField="PhoneNumber"
             DataValueField="PhoneId" />

          <
    phdb:EntityDataSource ID="AddressPhoneDataSource" runat="server"
             ProviderName="AddressPhoneProvider"
             EntityTypeName="PhDb.BLL.AddressPhone, PhDb.BLL"
             SelectMethod="GetByAddressId">
             <Parameters>
                <asp:ControlParameter name="EntityId" ControlID="AddressIdLabel" />
             </Parameters>
          </phdb:EntityDataSource>

          <
    phdb:ManyToManyListRelationship ID="AddressPhoneRelationship" runat="server">
             <PrimaryMember runat="server"
                DataSourceID="AddressDataSource"
                EntityKeyName="AddressId"
                EntityIndex='<%# DataBinder.Eval(Container, "PageIndex") %>' />
             <LinkMember runat="server"
                DataSourceID="AddressPhoneDataSource"
                EntityKeyName="AddressId"
                ForeignKeyName="PhoneId" />
             <ReferenceMember runat="server"
                DataSourceID="PhoneDataSource"
                ListControlID="PhoneList"
                EntityKeyName="PhoneId"
                EntityIndex='<%# DataBinder.Eval(Container, "PageIndex") %>' />
          </phdb:ManyToManyListRelationship>
       </td>
       <td style="width:10px;">&nbsp;</td>
       <td nowrap>
          <div><b>Facilities:</b></div>

          <
    asp:CheckBoxList ID="FacilityList" runat="server"
             DataSourceID="FacilityDataSource"
             DataTextField="FacilityName"
             DataValueField="FacilityId" />

          <
    phdb:EntityDataSource ID="AddressFacilityDataSource" runat="server"
             ProviderName="AddressFacilityProvider"
             EntityTypeName="PhDb.BLL.AddressFacility, PhDb.BLL"
             SelectMethod="GetByAddressId">
                <Parameters>
                   <asp:ControlParameter name="EntityId" ControlID="AddressIdLabel" />
                </Parameters>
          </phdb:EntityDataSource>

          <
    phdb:ManyToManyListRelationship ID="AddressFacilityRelationship" runat="server">
             <PrimaryMember runat="server"
                DataSourceID="AddressDataSource"
                EntityKeyName="AddressId"
                EntityIndex='<%# DataBinder.Eval(Container, "PageIndex") %>' />
             <LinkMember runat="server"
                DataSourceID="AddressFacilityDataSource"
                EntityKeyName="AddressId"
                ForeignKeyName="FacilityId" />
             <ReferenceMember runat="server"
                DataSourceID="FacilityDataSource"
                ListControlID="FacilityList"
                EntityKeyName="FacilityId"
                EntityIndex='<%# DataBinder.Eval(Container, "PageIndex") %>' />
          </phdb:ManyToManyListRelationship>
       </td>
    </tr>
    </table>

    </
    ItemTemplate>
    </
    asp:FormView>


    Bobby Diaz ------------------------------------------ Member of the .NetTiers team http://www.nettiers.com ------------------------------------------
    • Post Points: 5
  • 04-23-2006 11:55 PM In reply to

    • bdiaz
    • Top 10 Contributor
    • Joined on 02-20-2006
    • Houston, TX
    • Posts 504
    • Points 15,290

    Re: Using the ManyToManyViewRelationship Control

    Lastly, I wanted to show the codebehind class for the Address edit page.  Not much going on here...

    protected void Page_Load(object sender, EventArgs e)
    {
       FormUtil.ValidateSessionParam("PersonId", "Find.aspx");
       FormUtil.RedirectAfterUpdateCancel(EditFormView, "Address.aspx");
    }


    Bobby Diaz ------------------------------------------ Member of the .NetTiers team http://www.nettiers.com ------------------------------------------
    • Post Points: 65
  • 04-24-2006 6:20 AM In reply to

    • mike123
    • Top 10 Contributor
    • Joined on 02-25-2005
    • Toronto, Ontario
    • Posts 734
    • Points 17,040

    Re: Using the ManyToManyViewRelationship Control

    Bobby,

    This is impressive, thanks a lot!

    Michael

    Mike Shatny
    --------------------------------------------------------------
    Member of the .netTiers team http://www.nettiers.com
    --------------------------------------------------------------

    • Post Points: 35
  • 04-24-2006 3:01 PM In reply to

    Re: Using the ManyToManyViewRelationship Control

    Bobby, this is some killer stuff!  Big Smile [:D]

    Robert Hinojosa
    -------------------------------------
    Member of the Codesmith Tools, .netTiers, teams
    http://www.nettiers.com
    -------------------------------------
    • Post Points: 5
  • 04-25-2006 12:03 PM In reply to

    • sdavison
    • Top 150 Contributor
    • Joined on 01-25-2006
    • Posts 26
    • Points 805

    Re: Using the ManyToManyViewRelationship Control

    These samples are fantastic, thanks for posting them.  Can you also post the code behind the update/add new/cancel buttons, as well?  You also reference this thread from another post regarding hooking in the auditing fields, including setting the name of the user performing the insert/update, yet I don't see anything related to that in the code.  Did I miss it?
    • Post Points: 35
  • 04-25-2006 12:32 PM In reply to