EntityDataSource and Bind: What are those square brackets?
This post is about a small issue that I have seen in the forums and that arises often in cases in which EntityDataSource is used in combination with bound controls that use templates, like FormsView or a GridView with template based columns.
If you can create your page correctly, simply using the different drag & drop features and context menus provided by the design surface. However, in the end, some Bind expressions will get enclosed in square brackets that produce compile or run-time errors, then your code may look like this:
<EditItemTemplate>
<asp:DropDownList ID="CategoryDropDownList" runat="server"
DataSourceID="CategoryDataSource"
DataTextField="CategoryName"
DataValueField="CategoryID"
SelectedValue='<%# Bind("[Category.CategoryID]") %>'>
</asp:DropDownList>
</EditItemTemplate>
This annoyance may keep you blocked until you realize how simple the workaround is: just remove the square brackets!
People that watched my video here, may have noticed that I had to remove the square brackets manually around minute 8:10. I wish I had blogged about it then, but it wasn’t clear at the time I recorded that video that the issue would still be there in the RTM version.
Here is a short explanation:
In order to adapt entity objects that do not have foreign key properties to work better with ASP.NET databinding, we decided to wrap each entity returned with a databinding wrapper object that, among other things, flattens the members of EntityKeys in related entities (for more details on how and why the EntityDataSource returns wrapped entities you can go here).
The name of flattened reference keys are usually composed by the corresponding navigation property, plus the name of the property in the related end. For instance, in a Product, the key of the associated Category, will be exposed as “Category.CategoryID”. We decided to use dots to delimit the parts of the name because that plays well and is consistent with the use of dots in most programming languages, and also in Eval expressions, like the one used in the following code:
<ItemTemplate>
<asp:Label ID="CategoryLabel" runat="server"
Text='<%# Eval("Category.CategoryName") %>'>
</asp:Label>
</ItemTemplate>
The problem is that for the particular case of Bind (often used in template based databound controls to perform two-way databinding) the design time component of ASP.NET will catch property names that contain dots, and it will try to escape them by surrounding them with square brackets (leading to ta Bind expression of the form “[Categories.CategoryID]”).
Unfortunately, the rest of the ASP.NET components which need to evaluate the binding expression are actually not capable of parsing the square brackets escaping notation (i.e. for DataBinder.Eval() the brackets actually indicate that a lookup in an indexed property is necessary, and there is no indexed property in this case).
Given that the EntityDataSource in fact exposes property descriptors that contain dots in their names, the escaping is unnecessary. So, next time you find this issue, just remove the square brackets.
The good news is that the issue will be fixed in the next release.
Hope this helps!
Comments
Anonymous
March 18, 2009
Hi, this is great! I am having an issue though with databound properties from another object and found nothing about it on the web or the msdn documents. Say I have databound Customer.CommentID which I then want Eval(Comment.CommentText) How do I let grid view update the CommentText without rolling my own updating mechanism for each column in the RowUpdating event? Cheers, SarkieAnonymous
August 19, 2009
weird.. I have a foreign key that is being displayed in the gridview. it displays correctly as a BoundField, however when i convert it to a template field no data comes through. I have removed square brackets and tried both Bind and Eval but to no avail . any suggestionsAnonymous
August 19, 2009
I have figured out my weird issue. when i use templatefield in my grid view ... i have to use the "include" in the entity data source and add my related entities. When i use the bound column i do not have to specify the "include" weird *lolAnonymous
March 23, 2010
Hello, I removed bracked and it worked for update and inserting , but for view in itemtamplate which is in label it display always null . Can you help on this. RegardsAnonymous
April 01, 2010
When you say... The good news is that the issue will be fixed in the next release. Is that in relation to a service pack that will be available for VS 2008 or does it mean it won't be fixed until the release of VS 2010, because I see the problem is gone in VS 2010 RC.Anonymous
April 02, 2010
Hi Ron, The fix went into ASP.NET 4.0 in Visual Studio 2010.Anonymous
April 10, 2010
Anton, Sorry I did not see your comment before. If I understand correctly what you are describing, I imagine you might need to specify a graph path to include in the query executed by the data source, which you can do by setting the Include property. For instance, if you need to bring the category of a product you can specify Include="Category". The explanation for this is a little complicated too, but if you can stay with me, read on: if are using an ItemTemplate for view, and you are binding to a label control inside it with an Eval expression like "Category.CategoryName", Eval will try to to find the value of Category property, and then look for the value of the CategoryName property on it. If you don't explicitly ask for the Category property to be loaded (i.e. setting the Include property), and you are not using automatic lazy loading support in EF 4, you will end up with a null value in the Category property and Eval will just give up, resulting in an empty label.Anonymous
April 10, 2010
Jason, Wow, sorry I never saw your comment before. I usually rely on mail notification to manage the comments on my blog, but I never got yours. Part of the explanation for this is contained in the response to Anton. In ASP.NET Eval and Bind are different, and they are both different to the BoundField property. For instance, BoundField and Bind in write mode are able to locate the property descriptor the EntityDataSource exposes for flattened FK properties, in my example, there is going to be a property descriptor named "Category.CategoryID" along side "ProductID" and "ProductName". Eval, on the other side, when it sees an expression that contains a "." in it, automatically drills down in the graph of objects as I was explaining to Anton. So you need to use Include, or to enable lazy loading in EFv4 (althouth Include is going to cause less round trips to the database server). Incidentally, it is possible to get rid of all this "weirdness" in EFv4 if you use foreign key associations and you set EnableFlattening = false. Hope this helps, DiegoAnonymous
April 10, 2010
Sarkie, It has been a long time since you posted your comment, but I never saw a notification for it, so apologizes if I did not answer on time. EntityDataSource and ASP.NET WebForms DataSources in general only support updating first level properties on the bound object. EntityDataSource cannot really be used directly to update properties in related entities, i.e. if your EntityDataSource is bound to the Customers entity set, it can be used to update a property on Customer, like Customer.ContactName, but it cannot be used to update a property on a related entity, like Customer.Comment.CommentText. That said, EntityDataSource can use flattening to expose FK values for independent associations (a kind of association supported by Entity Framework in which FKs don’t appear as scalar properties in entities), and for complex types. So, if you were able to change your model to make Comment a Complex Type in Customer rather than an Entity Type, you could use EntityDataSource directly to update it. As you said, in most cases, you will need to roll your own mechanism to enable editing a property in another entity. One approach you could consider using is to place an EntityDataSource (bound to the Comments entity set and with appropriate Where condition) inside the update and insert item templates for this property. Hope this helps, DiegoAnonymous
September 27, 2010
The comment has been removedAnonymous
October 03, 2010
Very thanks,your solution have issue for me.