locked
edit.aspx with two cached foreign keys to the same table RRS feed

  • Question

  • User1536446687 posted

    I have a table Projects with 2 foreign keys: Contact, Owner to the same table People

    People, PeopleId <-> ContactId, Projects

    People, People Id <-> OwnerId, Projects

    Now the following pages are working fine:

    - List.aspx show both correct value for Contact and Owner

    - Details.aspx show both correct value for Contact and Owner

    However Edit.aspx shows always the Owner for both of those fields.

    My Edit.aspx code behind:

       /// <summary>
        /// Edit page
        /// </summary>
        public partial class Edit : Page
        {
            /// <summary>
            /// Gets or sets dynamic table
            /// </summary>
            protected MetaTable Table { get; set; }
    
            /// <summary>
            /// On init page event
            /// </summary>
            /// <param name="sender">The parameter is not used.</param>
            /// <param name="e">The parameter is not used.</param>
            protected void Page_Init(object sender, EventArgs e)
            {
                Table = DynamicDataRouteHandler.GetRequestMetaTable(Context);
                FormView1.SetMetaTable(Table);
                DetailsDataSource.EntityTypeFilter = Table.EntityType.Name;
            }
    
            /// <summary>
            /// On loading page event
            /// </summary>
            /// <param name="sender">The parameter is not used.</param>
            /// <param name="e">The parameter is not used.</param>
            protected void Page_Load(object sender, EventArgs e)
            {
                Title = Table.DisplayName;
                DetailsDataSource.Include = Table.ForeignKeyColumnsNames;
            }
        }

     

    I added an event to the FormView -> FormView1_DataBound and determined that already an invalid value is being passed to it.

    Is it possible that dynamic data extension is confused because both fields are of the same type (People, EntityFramework model)?

    How can I debug this further? At some point this value is changed (if I retrieve value directly from the EF context I get correct values).

    Thursday, January 30, 2014 9:02 AM

Answers

  • User1536446687 posted

    The issue was that collections of both DropDownLists were being cached under the same guid. Once the first control has been loaded the other control just took the data out of cache, which should be the case logically but does not work as the selected values for both control are diffrent and overwrite each other.

    As usual the solution turned out to be quite simple. I've changed cache's unique id to 

    string parentTableName = this.ForeignKeyColumn.DisplayName;

    It's not perfect because both columns are cached separately even though it's the same data, but the selected values are diffrent and in my opinion with dynamic data it would be difficult to implement diffrently.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 3, 2014 5:43 AM

All replies

  • User-330204900 posted

    Hi Adam, are you using Entity Framework or Linq to SQL? and have you renamed the Navigation Properties in the Designer or do they both have the name?

    This is a common situation and works out of the box, but may have issues if the data model is not standard?

    Thursday, January 30, 2014 11:08 AM
  • User1536446687 posted

    Thank you for the reply.

    I'm using EntityFramework and the Navigation Properties have diffrent names.

    After further debugging I narrowed it down to ForeignKey_Edit.ascx

    <asp:Label runat="server" ID="ValueLbl"></asp:Label>
    <asp:DropDownList ID="CustomID" runat="server" CssClass="DDDropDown chosen-select">
    </asp:DropDownList>
    
    <asp:RequiredFieldValidator runat="server" ID="RequiredFieldValidator1" CssClass="DDControl DDValidator" ControlToValidate="CustomID" Display="Static" Enabled="false" />
    <asp:DynamicValidator runat="server" ID="DynamicValidator1" CssClass="DDControl DDValidator" ControlToValidate="CustomID" Display="Static" />

    Speciffically to OnDataBinding event:  

            protected override void OnDataBinding(EventArgs e)
            {
                using (MiniProfiler.Current.Step("ForeignKey_EditField OnDataBinding"))
                {
    
                    base.OnDataBinding(e);
    
                    string selectedValueString = GetSelectedValueString();
                    ListItem item = CustomID.Items.FindByValue(selectedValueString);
                    if (item != null)
                    {
                        ValueLbl.Text = selectedValueString;
                        CustomID.SelectedValue = selectedValueString;
                    }
                }
            }

    For some reason the ValueLbl.Text is set correctly, but CustomID.SelectedValue is overwritten when the second control (second FK_Edit.ascx on the page I mean) is loaded. As if both CustomID controls are being rendered with the same ID and are treated as one.

    Friday, January 31, 2014 3:49 AM
  • User-330204900 posted

    Can you post the T-SQl to create the table to test this please and I check it out here as this could be a bug?

    Friday, January 31, 2014 6:03 AM
  • User1536446687 posted

    The tables are fairly simple, and I set all the assosiations in the entity model. The db is of course a lot bigger and complex but the reliationship between the tables with issues is as simple as in this diagram

    Anyway I created a basic dynamic data web application from scratch with the database above and there was no issue. I even reused the entity model and database from my application in the basic one and this issue does not occur there so it must be narrowed down to my application only.

    I don't know how could it but I suspect Chosen plugin (http://harvesthq.github.io/chosen/) could be messing with my code. I tried disabling it for Edit and ForeignKey_Edit, but it didn't work, but maybe I need to get rid of it completely.

    I'd appreciate any further suggestions, though I do realize the it's hard to do anything without being able to see the code at least...

    Friday, January 31, 2014 8:15 AM
  • User1536446687 posted

    Ok, I've narrowed it down completely, but I don't have time today to fix it but it should be fairly easy from this point on.

    The issue is in this method for the ForeignKey_EditField and it concerns caching and retrieving the list from the cache:

            protected void Page_Load(object sender, EventArgs e)
            {
                using (MiniProfiler.Current.Step("ForeignKey_EditField Page_Load"))
                {
                    if (DropDownList1.Items.Count == 0)
                    {
                        if (Mode == DataBoundControlMode.Insert || !Column.IsRequired)
                        {
                            DropDownList1.Items.Add(new ListItem("[Not Set]", ""));
                        }
    
                        using (MiniProfiler.Current.Step("ForeignKey_EditField population"))
                        {
                            string parentTableName = this.ForeignKeyColumn.ParentTable.DataContextPropertyName;
    
                            // check if table should be cacheable
                            if (FieldTemplatesHelper.IsCacheable(parentTableName))
                            {
                                // check if item is in cache
                                var items = FieldTemplatesHelper.GetItemsFromCache(parentTableName,  Cache);
    
                                // item is not in cache
                                if (items == null)
                                {
                                    PopulateListControl(DropDownList1);
    
                                    // add to cache
                                    FieldTemplatesHelper.AddToCache(parentTableName, DropDownList1.Items, Cache);
                                }
                                // item is in cache
                                else
                                {
                                    // remove all from dropdown
                                    DropDownList1.Items.Clear();
                                    // add cached items
                                    DropDownList1.Items.AddRange(items.Cast<ListItem>().ToArray());
    
                                }
                            }
                            else
                            {
                                // if item should not be in cache load it in regular way
                                PopulateListControl(DropDownList1);
                            }
                        }
                    }
    
                    using (MiniProfiler.Current.Step("Adding ForeignKey_EditField validators"))
                    {
                        using (MiniProfiler.Current.Step("Add required field validators"))
                        {
                            SetUpValidator(RequiredFieldValidator1);
                        }
    
    
                        using (MiniProfiler.Current.Step("Add dynamic validators"))
                        {
                            SetUpValidator(DynamicValidator1);
                        }
    
                    }
                }
            }

    Thanks for your time and brainstorming! I'll post my fix on Monday for future generations Wink

    Friday, January 31, 2014 9:46 AM
  • User-330204900 posted

    That does not look like the standard code for the foreign key column field template not sure why it has been changes this should work out of the box though.

    Friday, January 31, 2014 9:56 AM
  • User1536446687 posted

    Yes, the standard code works just fine, this one has been introduced to cache the data in the dropdown because there was a lot of it. It sped up the loading time significantly, but for this particular case it also messed up.

    Anyway thanks for the input and you've been an excellent "rubber duck" if you don't mind my saying ;)

    Monday, February 3, 2014 4:04 AM
  • User-330204900 posted

    Hi Adam I usually use the old AutoComplete from an early sample the team did this uses the AjaxControl Toolkit autocomplete to filter the contents. if you think this would be a help I can send you the field template as is no longet on codeplex.

    Monday, February 3, 2014 5:18 AM
  • User1536446687 posted

    The issue was that collections of both DropDownLists were being cached under the same guid. Once the first control has been loaded the other control just took the data out of cache, which should be the case logically but does not work as the selected values for both control are diffrent and overwrite each other.

    As usual the solution turned out to be quite simple. I've changed cache's unique id to 

    string parentTableName = this.ForeignKeyColumn.DisplayName;

    It's not perfect because both columns are cached separately even though it's the same data, but the selected values are diffrent and in my opinion with dynamic data it would be difficult to implement diffrently.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 3, 2014 5:43 AM
  • User-330204900 posted

    Hi Adam, are you cascading from dropdown to the next or is this two fields using the same field template? just being curious :)

    Monday, February 3, 2014 6:02 AM