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