Many to many with dynamic data

Last post 03-09-2008 5:49 PM by shady.sayed. 4 replies.

Sort Posts:

  • Many to many with dynamic data

    02-17-2008, 2:52 PM
    • Member
      3 point Member
    • shady.sayed
    • Member since 02-17-2008, 2:21 PM
    • Posts 5

     Hello there,

    I was trying to make a many to many relation in a dynamic data project and I have faced some problems

    Assume that I have three tables

    1-Products

    2-Tags (just assume that this table will contain very few entries).

    3-ProductsToTags (that does the many to many relation between tags and products ).

     

    I wanted to be able to select the tags applied to a product from the Products page

    the idea is to display a comma separated list of tags when viewing the product, and display a ListBox of tags when editing the product. 

    so the first thing to do is to redirect the rendering from the standard Children.ascx into some new control lets name it TagList.ascx, and TagList_Edit.ascx

     and add a code behind file for the dbml file and add a RenderHint

     

    [RenderHint("ProductsToTags ", "TagList")]

    public partial class Product

    {}

     

    The read only control is pretty simple; it will contain a simple label named Label1 and as I said earlier it will display a comma separated list of tags

    so on the Page_Load event we would do something like the following

           DynamicMetaChildrenMember column = (DynamicMetaChildrenMember)MetaMember;

            IQueryable<ProductsToTag> p2d= column.OtherMetaTable.Query as IQueryable<ProductsToTag>;

            var tagNames = p2d.Select(detail => detail.Tag.Name);
            StringBuilder sb = new StringBuilder();

            // start iterating and create the string (simple)

     

    the really hard part that I am unable to do is to make the edit control TagList_Edit.ascx

    what I did is that I have added in this TagList Control a multiselect  ListBox and the idea is to populate it with all the tags and select only the tags that are applied to the current product

     
    Getting all the tags is very simple but what I can't do is to get the current productID so that when a user selects new tags through this ListBox I can create new Entries in the ProductsToTags with the TagID that I obtained from the ListBox and the Product ID that I can not obtain yet :(

     

    So the question is can anyone tell me how to get the ID of the current row being edited in a DynamicGridView so that I can use it in one of it's edit child controls ???

     

  • Re: Many to many with dynamic data

    02-17-2008, 6:17 PM
    Answer
    • Contributor
      5,813 point Contributor
    • davidebb
    • Member since 06-11-2002, 12:31 PM
    • Redmond, WA
    • Posts 1,161
    • AspNetTeam

    You can get the current data item (in your case the Product) by simply calling DataItem (on the base class FieldTemplateUserControlBase).  One you have the Product, getting its primary key should be easy.

    As an aside, what would be very interesting is to try to write a generic version of this field template.  i.e. one that would work automatically for any similar relationship.  The hard part in doing this is to build the LINQ expression that work for any data type.  It can be done, but is not as simple as regular LINQ expressions.

    This would be a good sample to have at some point.  I'll put in on the list!

    thanks,
    David

  • Re: Many to many with dynamic data

    02-18-2008, 4:59 AM
    • Member
      3 point Member
    • shady.sayed
    • Member since 02-17-2008, 2:21 PM
    • Posts 5

     Thank you David,

    I have tried to call the DataItem property but I got an Exception saying

    "Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control."

    it seems that child tables are not bound 

    thanks,

    Shady 

  • Re: Many to many with dynamic data

    02-18-2008, 9:12 AM
    • Member
      3 point Member
    • shady.sayed
    • Member since 02-17-2008, 2:21 PM
    • Posts 5

     Sorry, My mistake I called it before the control is bound

    I overrided Databind method and in it after calling the base implementation I inserted the code that depends on the current product

     

     public override void DataBind()
        {
            base.DataBind();
            Product currenttProduct = (Product)this.DataItem;

           //use the currentProduct here
       }
     

  • Re: Many to many with dynamic data

    03-09-2008, 5:49 PM
    • Member
      3 point Member
    • shady.sayed
    • Member since 02-17-2008, 2:21 PM
    • Posts 5

    I have finally had some time to work back on dynamic data, and I finished the many-to-many Implementation and I wanted to share my thoughts.

    It seems that the best way to Extract data from a dynamic control and attach it to the model is to override the ExtractValues method (at least this is the way it is implemented in the default templates). the problem is how to attach the data into the Product entity. to do so I had to add to it a new property as follows

     partial class Product

    {

          public IEnumerable<int> TagIds {get;set;}

    }

    so, in the TagList_Edit.ascx I have overriden the ExtractValues method

     

    protected override ExtractValues(IOrderedDictionary dictionary)

    {

          //lstTags is the list that contains the tags that the user has selected

          dictionary["TagIds"] = (from selectedItem. lstTags.Items.OfType<ListItem>()

                                          where selectedItem.Selected == true

                                          select int.Parse(selectedItem.Value)).ToList(); //something tells me I should not deferr this

    }

     

    now that we have the extracted values; we need to add the selected Ids to the database at some point. My first shot was at the DataContext, by implementing the partial method pair; InsertProduct/UpdateProduct, but the problem is that UpdateProduct will not be called unless one of the columns in the Product Entity actually changes and not just the selected tags (i.e. will not be called unless something like the ProductName changes and not something that I have attached to the entity like the TagIds).

    So Eventhough I did not like putting this logic in the UI template; I turned into the Template for the Products table (ListDetails.aspx for the Products)

    I hooked into the updating and inserting for the two datasources in the template but I have faced one little problem again with the updating.

     at first I did the following

    void DataSource_updating(object sender, LinqDataSourceUpdateEventArgs e)

    {

            Product p = (Product ) e.NewObject;

            //do some logic to get the list of tag ids to add and tag ids to delete

            foreach(int idToAdd in idsToAdd)

            {

                    //for some reason the following line does not work while updating, only works when adding a new Product

                    p.ProductsToTags.Add( new ProductsToTag{ TagId = idToAdd});

             }

    }

     

    but the tags were not added and I don't know why (maybe It is something I do not understand about linq), I had to create a context on my own and do it like the following

    void DataSource_updating(object sender, LinqDataSourceUpdateEventArgs e)

    {

            Product p = (Product ) e.NewObject;

            MyDBDataContext context =new MyDBDataContext ();

            Product pInContext = context.Products.Where(pr=>pr.ProductId == p.ProductId);

           //Continue with the context

    }

     

    and I finally had my many to many working.

    The things that I do not like about what I did is the following:

    1. The solution worked only for one (many-to-many). if there are Multiple (many-to-many) relations in the Products table I will have to redo the solution for each relation
    2. the logic is separated between the FieldTemplate control and the ListDetails Template, I believe it should only be in the FieldTemplate

     

    I think it whould have been better if the ExtractValues method took something other than a dictionary. maybe allowed for passing logic that will be called later (i.e. a delegate or an Interface).

    davidebb:

    As an aside, what would be very interesting is to try to write a generic version of this field template.  i.e. one that would work automatically for any similar relationship.  The hard part in doing this is to build the LINQ expression that work for any data type.  It can be done, but is not as simple as regular LINQ expressions.

    David mentioned building Linq Expression, I really do not know what does that mean. could you please elaborate a bit maybe tell me where to build it. and If it is fed into the ExtractValues method can you please tell me how to insert it into the dictionary.

Page 1 of 1 (5 items)