Binding ASPxGridView to entity properties

Posts   
 
    
colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 12-Sep-2007 11:21:57   

I am using self service model with LLBLGen version 2.0 and trying to bind to the DevExpress gridview component ASPxGridView

(I know that this is not directly an LLBLGen problem as this worked with the standard asp:GridView before but I am hoping you might be able to steer me in the right direction)

Everything seems to work for fields that belong to my "primary" entity (the type held by my datasource). However, when I try to display values from entities that are related to the "primary" entity type I get the following error at runtime:

System.Web.HttpException: DataBinding: 'DevExpress.Web.Data.WebDataRow' does not contain a property with the name 'Applicant'.

The code from my .aspx file is


<dxwgv:GridViewDataTextColumn Caption="Applicant" FieldName="ApplicantId" VisibleIndex="1">
    <DataItemTemplate>
        <%# GetApplicantName(Eval("Applicant")) %>
    </DataItemTemplate>
</dxwgv:GridViewDataTextColumn>

The example from the DevExpress tutorial is as follows:

<dxwgv:GridViewDataTextColumn FieldName="Address" VisibleIndex="2" Caption="Street">
             <DataItemTemplate>
                 <dxe:ASPxTextBox ID="ASPxTextBox1" runat="server" Text='<%#Eval("Address.Street")%>' Width="100%">
                 </dxe:ASPxTextBox>
             </DataItemTemplate>
         </dxwgv:GridViewDataTextColumn>

... but I can't see why mine doesn't work (assuming this does).

Thanks in advance!

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 12-Sep-2007 11:45:39   

The following is an example of how to bind the Category.CategoryName to a Grid displaying Products.

'<%# DataBinder.Eval(Container.DataItem, "Category.CategoryName")%>'
colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 13-Sep-2007 00:19:30   

Changing from the 'shortcut' Eval syntax to the explicit DataBinder.Eval() made no difference.

I built a completely new demo project with a small test database to demonstrate this problem.

The database contains 3 tables: Product contains columns ProductId (PK bigint), Name, Cost, ManagerId ProductManager contains columns ManagerId (PK bigint), Name Inventory contains columns InventoryId (PK bigint), ProductId (unique key), Location, Quantity

I created 2 pages: the first uses a standard asp:GridView to display the product and related information while the second uses the DevExpress GridView (page code included below).

The first page displays the data correctly while the page DevExpressView.aspx receives an error saying:

Exception Details: System.Web.HttpException: DataBinding: 'DevExpress.Web.Data.WebDataRow' does not contain a property with the name 'ProductManager'.

Source Error:

Line 32: <dxwgv:GridViewDataTextColumn Caption="Manager" FieldName="ManagerId" VisibleIndex="3"> Line 33: <DataItemTemplate> Line 34: <asp:Label ID="Label1" runat="server" Text='<%# Eval("ProductManager.Name") %>'></asp:Label> Line 35: </DataItemTemplate> Line 36: </dxwgv:GridViewDataTextColumn>

Is there something different about entity properties that obtain a related entity that might prevent the ASPxGridView from reading them (I notice that the ProductManager property has an attribute of Browsable set to false)???

ProductManager is a property on the Test.EntityClasses.ProductEntity class ... here is a code excerpt showing the Property :

      [Browsable(false)]
      public virtual ProductManagerEntity ProductManager
      {
           get   { return GetSingleProductManager(false); }
           set
           {
                if(base.IsDeserializing)
                {
                     SetupSyncProductManager(value);
                }
                else
                {
                     if(value==null)
                     {
                          if(_productManager != null)
                          {
                               _productManager.UnsetRelatedEntity(this, "Product");
                          }
                     }
                     else
                     {
                          ((IEntity)value).SetRelatedEntity(this, "Product");
                     }
                }
           }
      }

Please let me know if there is anything else that I can give you!

Here is the code for the first page (this one works):

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register Assembly="SD.LLBLGen.Pro.ORMSupportClasses.NET20" Namespace="SD.LLBLGen.Pro.ORMSupportClasses"
    TagPrefix="llblgenpro" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>GridView Implementation</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/DevExpressView.aspx">DevExpress View</asp:HyperLink>
        <div>
            <llblgenpro:LLBLGenProDataSource ID="GridViewDS" runat="server" DataContainerType="EntityCollection"
                EntityCollectionTypeName="Test.CollectionClasses.ProductCollection, Test">
            </llblgenpro:LLBLGenProDataSource>
            <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductId"
                DataSourceID="GridViewDS" Width="100%">
                <Columns>
                    <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
                    <asp:BoundField DataField="Cost" HeaderText="Cost" SortExpression="Cost" />
                    <asp:TemplateField HeaderText="Manager" SortExpression="ManagerId">
                        <ItemTemplate>
                            <asp:Label ID="Label1" runat="server" Text='<%# Eval("ProductManager.Name") %>'></asp:Label>
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Inventory Location">
                        <ItemTemplate>
                            <%# Eval("Inventory.Location") %>
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Quantity">
                        <ItemTemplate>
                            <%# Eval("Inventory.Quantity") %>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
        </div>
    </form>
</body>
</html>

.. and here is the code for the second page (this one gets the error):

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DevExpressView.aspx.cs" Inherits="DevExpressView" Debug="true"%>

<%@ Register Assembly="DevExpress.Web.ASPxEditors.v7.2, Version=7.2.3.0, Culture=neutral, PublicKeyToken=9b171c9fd64da1d1"
    Namespace="DevExpress.Web.ASPxEditors" TagPrefix="dxe" %>
<%@ Register Assembly="SD.LLBLGen.Pro.ORMSupportClasses.NET20" Namespace="SD.LLBLGen.Pro.ORMSupportClasses"
    TagPrefix="llblgenpro" %>
<%@ Register Assembly="DevExpress.Web.ASPxGridView.v7.2, Version=7.2.3.0, Culture=neutral, PublicKeyToken=9b171c9fd64da1d1"
    Namespace="DevExpress.Web.ASPxGridView" TagPrefix="dxwgv" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Standard ASP.Net View</asp:HyperLink>
        <div>
            <llblgenpro:LLBLGenProDataSource ID="GridViewDS" runat="server" DataContainerType="EntityCollection"
                EntityCollectionTypeName="Test.CollectionClasses.ProductCollection, Test">
            </llblgenpro:LLBLGenProDataSource>
            <dxwgv:ASPxGridView ID="ASPxGridView1" runat="server" AutoGenerateColumns="False"
                DataSourceID="GridViewDS" KeyFieldName="ProductId" Width="100%">
                <Columns>
                    <dxwgv:GridViewDataTextColumn Caption="ProductId" FieldName="ProductId" ReadOnly="True"
                        VisibleIndex="0">
                        <EditFormSettings Visible="False" />
                    </dxwgv:GridViewDataTextColumn>
                    <dxwgv:GridViewDataTextColumn Caption="Name" FieldName="Name" VisibleIndex="1">
                    </dxwgv:GridViewDataTextColumn>
                    <dxwgv:GridViewDataTextColumn Caption="Cost" FieldName="Cost" VisibleIndex="2">
                    </dxwgv:GridViewDataTextColumn>
                    <dxwgv:GridViewDataTextColumn Caption="Manager" FieldName="ManagerId" VisibleIndex="3">
                        <DataItemTemplate>
                            <asp:Label ID="Label1" runat="server" Text='<%# Eval("ProductManager.Name") %>'></asp:Label>
                        </DataItemTemplate>
                    </dxwgv:GridViewDataTextColumn>
                    <dxwgv:GridViewDataTextColumn Caption="Inventory Location" VisibleIndex="4">
                        <DataItemTemplate>
                            <%# Eval("Inventory.Location") %>
                        </DataItemTemplate>
                    </dxwgv:GridViewDataTextColumn>
                    <dxwgv:GridViewDataTextColumn Caption="Quantity" VisibleIndex="5">
                        <DataItemTemplate>
                            <%# Eval("Inventory.Quantity") %>
                        </DataItemTemplate>
                    </dxwgv:GridViewDataTextColumn>
                </Columns>
                <SettingsPager Visible="False">
                </SettingsPager>
            </dxwgv:ASPxGridView>
        </div>
    </form>
</body>
</html>

colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 13-Sep-2007 00:29:24   

More information ..... I hand edited the Entity class for Product and changed the Browsable attribute to true and it worked!!!

So now my questions are:

1) Does this have some other negative impact ? 2) If not, how can I generate my code so that this flag is set to true for all other 'relation' properties?

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 13-Sep-2007 11:41:23   

I hand edited the Entity class for Product and changed the Browsable attribute to true and it worked!!!

So now my questions are:

1) Does this have some other negative impact ? 2) If not, how can I generate my code so that this flag is set to true for all other 'relation' properties?

The attribute is placed on properties mapped on relations because otherwise they will end up as columns inside the grid.

Another solution: If you want to display the ProductManager.Name when you display fields from the Product entity. You may use the Designer to map ProductManager.Name as a field mapped or related field (eg. ProductManagerName) in the Product Entity.

colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 18-Sep-2007 10:38:22   

I took this problem up with the guys from DevExpress and sent them a complete sample project including a test database on SQLServer and the LLBLGen generated code ... After looking into this problem their response is as follows:

We have researched the problem, and found that this is not our issue. The DataSource you are using supports the ITypedList interface. If you typecast it to this interface and obtain the PropertyDescriptors collection using the GetItemProperties method, you will notice that there is no ProductManager property. I am afraid the only solution is to remove the Browsable attribute from this property.

Is it true that this is a problem with the LLBLGen generated code? Should this property be included in the PropertyDescriptors collection as they state? If not, how is the Grid supposed to verify that the property is valid?

I am not prepared to expose every field of every related object that I want to navigate to in my whole project!!! I have over 120 different entities so that would be absolute craziness from my point of view. If this is just a workaround for a bug in the implementation of the ITypedList interface I will just have to modify the code generation template and set Browsable to true.

I feel a little caught in the middle here ... please help.

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 18-Sep-2007 11:04:48   

Please read my previous post.

Posts: 2
Joined: 18-Sep-2007
# Posted on: 18-Sep-2007 21:08:03   

Walaa wrote:

Please read my previous post.

Walaa,

I don't think your solution is appropriate : having to duplicate all the child properties you need to display inside the parent entity does not look feasible on any large application.

I think the problem is similar to this post : http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=10802&StartAtMessage=0&#62930

Any hints on properly navigating entity relations in a two way databinding scenario would be helpful.

colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 18-Sep-2007 23:15:08   

Walaa,

Did you actually READ my response?? Perhaps I need to make it clearer? My take on the reply from DevExpress is that the LLBLGen datasource does not correctly implement the interface and therefore does not make the Properties that I have ALREADY defined available to the grid.

I am not interested in pointing fingers but I AM interested in correctly identifying where the problem lies and getting it addressed.

Before this post, the support from LLBLGen has been awesome and, as a result, I have recommended your product to a number of other people. So, perhaps you were having a bad day ... and perhaps I am misunderstanding what you meant.

Just to clarify - the field that the grid is unable to access is a field representing a relationship to another entity (e.g. Product.ProductManager refers to the related entity ProductManager).

As an experiment, I attempted to create a field on Product to expose the ProductManager.Name field. Clicking Add New on the Fields on related fields tab would not allow this (the only field I could add to product was the ID field from a related entity that refers to the Product.ID as a foreign key).

However, even if I could do this for my project, I consider it to be EXTREMELY poor engineering practice to create a field in entity A to expose every field I need to access in related entities B, C and D. What if entity F also has a relationship to B? Am I also supposed to create another duplicate field in F as well? Please .. let's be real!

I'd appreciate it if you could address the real question ... is there a problem with the implementation of the interface on this datasource? If there is .. fine. Hopefully that'll be addressed soon. If not, I need something a little more concrete to go back to DevExpress with.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 19-Sep-2007 12:10:48   

colincsb wrote:

Walaa,

Did you actually READ my response?? Perhaps I need to make it clearer? My take on the reply from DevExpress is that the LLBLGen datasource does not correctly implement the interface and therefore does not make the Properties that I have ALREADY defined available to the grid.

Erm, it DOES implement the interface correctly.

Our ITypedList implementation is done on the EntityView(2) objects. This implementation filters out all properties which are marked with Browsable(false). This is done to prevent some properties ending up as columns in bound grids.

So what DevExpress reported back to you is correct: the properties marked with Browsable(false) are filtered out. This is by design, as not all users work with fancy grid controls.

The problem is that if we would remove the attribute, EVERYONE has to design their grids from that point, because columns you don't want are showing up as well in a databinding setup where columns are automatically discovered.

It's a bit problematic, because removing it will give problems but keeping it will give problems to people who want to navigate entities in the SAME rowset of the grid.

We've added fields mapped onto related fields for this purpose, so for example you can map 'Customer.CompanyName' as 'CompanyName' in Order. Therefore you don't have to navigate from Order to Customer to access CompanyName, IF you want to show it in the same rowset in the grid, because that's the situation where this takes place.

If we would remove the Browsable(false) attribute, objects would be showing up as columns and you have to alter the grid's columns as well, which can be cumbersome if you just want to see the fields of an entity.

It's not really solvable. The matter is that the attribute on a property is a 'one size fits all' approach which is forced upon us by the MS databinding architecture. There's no way to specify this per-situation, as that would require an MVC approach and that's not really how asp.net is build with.

I am not interested in pointing fingers but I AM interested in correctly identifying where the problem lies and getting it addressed.

Before this post, the support from LLBLGen has been awesome and, as a result, I have recommended your product to a number of other people. So, perhaps you were having a bad day ... and perhaps I am misunderstanding what you meant.

I think you did, as walaa explained why this is done. I've given you the background of it in this post and I hope you'll understand our position. I do understand that it sucks from your point of view and I can understand that you want to change it or have it changed in our code.

Just to clarify - the field that the grid is unable to access is a field representing a relationship to another entity (e.g. Product.ProductManager refers to the related entity ProductManager).

As an experiment, I attempted to create a field on Product to expose the ProductManager.Name field. Clicking Add New on the Fields on related fields tab would not allow this (the only field I could add to product was the ID field from a related entity that refers to the Product.ID as a foreign key).

Is 'Name' an inherited field? Are you using v2.0? In v2.0 it wasn't possible to map a field onto a related field if that field was inherited. In v2.5 we added that.

However, even if I could do this for my project, I consider it to be EXTREMELY poor engineering practice to create a field in entity A to expose every field I need to access in related entities B, C and D. What if entity F also has a relationship to B? Am I also supposed to create another duplicate field in F as well? Please .. let's be real!

Why don't you call Redmond and tell them their databinding design sucks? Because that's the real cause here: the BOUND datacontainer (the entity view) has no idea what calls it, what context it is used in. All it knows is: produce the property descriptors for the elements inside you. So it does that. We HAD TO add a filter, as I explained above. There's no way we can know what to filter other than based on an attribute, simply because the datacontainer doesn't know what the context is!

So if in one scenario, field A, B and C should be filtered out and in another scenario, field B has to be visible, you will understand that the design of databinding isn't capable of doing that. Why? Because the control you bind to connects to the container DIRECTLY without telling it what the scenario is. So there's no controller in between.

Don't think I don't hate this design forced upon framework developers. I hate it, simply because I've spend literarly months of work on getting it 'working' with the lack serious docs or any flexibility. (my article about implementing ITypedList is often used as a reference how to implement it, go figure). I don't want databinding code inside the entities, but I have to because there's no other way without MVC and .NET databinding doesn't support MVC unless everything is done through an external MVC framework.

So, one could argue: Why not put a custom filter into the object so you can write the filter yourself? Sure, that sounds nice on paper. But when will you do that, in a design time scenario? Or at runtime when there's NO CODE, because someone over at redmond thought that declarative HTML is enough to write applications?

And it gets worse: so you bind customers to the grid and say 'DataMember' is 'Orders'. Oops... you now have to inject the filter for ORDERS into ... where.. ? Orders? Or Customers? Still into customers! Because the ITypedList implementation of the bound OBJECT does the discovery, no matter what kind of REAL object deep down into the graph is actually bound to the grid. That's not something we cooked up, it's how ITypedList works.

The only solution is that there's a controller in the middle, which is controllable in all scenario's. Unfortunately, the databinding design of .NET isn't suitable for that IF you want to keep the rest of the win/webform framework alive.

No, having a way to specify this in the designer isn't going to cut it. Because that would still be a one-size-fits-all approach: because it would still not control the visibility of the property based on the context it is NEEDED in, it would control the visibility in ALL scenario's, which gives the same problems as we have now.

I'd appreciate it if you could address the real question ... is there a problem with the implementation of the interface on this datasource? If there is .. fine. Hopefully that'll be addressed soon. If not, I need something a little more concrete to go back to DevExpress with.

If I could address the real issue, I'd have done so already, but it's out of my hands: we have just 1 little attribute on a property for ALL scenario's an entity can EVER be used in. That's of course not possible, however it's all we can offer. So we filter on that attribute because it gives most of our users the environment they want.

Some users, like you and others, run into the limitations of this: they need to have a property descriptor reported which is filtered out. What to do? It's picking between a rock and a hard place.

We tried to solve it with the fields mapped onto related fields. Not a stellar solution, it doesn't go further than 1 hop, but alas, it's better than nothing.

I hope you understand the position we're in. If I could remove ALL databinding oriented code from the entities, I would do it TODAY. But we can't and therefore we have to live with the limitations. This issue is one of them, and it's not solvable in such a way that it is solved for every possible scenario: there are always scenario's left out: if we remove the attribute, the people who use automatic column discovery have a big problem, if we keep it, you have a problem. If we make the attribute optional in the designer, it will give a false sense of that it is solved, but it's not: you will still have scenario's where you don't need the column then but you will end up with it in the grid, causing frustration as well.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 19-Sep-2007 12:37:36   

Additional remark about pluggable filters: as the container bound to the grid directly (e.g. customer collection, which binds via its defaultview) has to report the property descriptors of ALL elements in the ENTIRE graph (and that without any data!, just types), a pluggable filter has to work on all elements in the entire graph, so in all bands in the grid (if a grid with multiple bands is used) the proper properties are reported. This of course goes wrong with 1 filter, so a filter per type has to be specified, but that also goes wrong if you for example bind Customers, Orders, and Customer - Employees - Orders, which are all in the same graph. Which order collection to pick for a filter?

And then we haven't even addressed the design time approach where plugging in filters for the DESIGN time experience isn't possible in code, because that's not ran, so it has be done inside a designer... but how? the types of these filters perhaps aren't written yet...

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 19-Sep-2007 13:12:40   

RenaudMartinon wrote:

Walaa wrote:

Please read my previous post.

Walaa,

I don't think your solution is appropriate : having to duplicate all the child properties you need to display inside the parent entity does not look feasible on any large application.

I think the problem is similar to this post : http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=10802&StartAtMessage=0&#62930

Any hints on properly navigating entity relations in a two way databinding scenario would be helpful.

I think there's no other solution.

Btw, I think the problem isn't as big as you make it out to be: the # of related fields to view as well isn't enormous. Sure, they're there, but you're not facing thousands of fields to map. And even then: it's either in the llblgen pro designer OR in the grid designer.

Btw2: Microsoft also filters. ObjectDataSource isn't usable with types which implement ICustomTypeDescriptor in a design time scenario (also with bindingsource in winforms). THey have a hardcoded filter in their schema objects returned to the grid from a datasourcecontrol in a design time scenario. I know this because I had to re-implement their classes because I couldn't use theirs due to this limitation.

Welcome to Hell^H^H^H^Hthe world of databinding wink .

Frans Bouma | Lead developer LLBLGen Pro
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 19-Sep-2007 13:14:26   

RenaudMartinon wrote:

Walaa,

I don't think your solution is appropriate : having to duplicate all the child properties you need to display inside the parent entity does not look feasible on any large application.

From the UI point of view: I think it is only in extreme rare cases where you want to display all related entities fields along with the main entity fields in a 2-way databinding scenario. Most of the cases I've seen during my development or support on this forums, only very few fields (if not one or two) are needed to be displayed from the related entities. Example displaying the CategoryName of a Product. But I've never seen someone asking about displaying all the fields from the all the related entities.

From the Database and performance point of view: Exposing all related fields would execute n+1 different queries (n being the number of related entities) to display a grid for example, which might not be the best thing you want to do. In this case I personally recommend droping off the 2 way databinding and use a TypedList or a dynamicList. (Which will also be cumbersome to design or code if you need this for each and every entity you are going to display, which is a very wierd case)

colincsb wrote:

Before this post, the support from LLBLGen has been awesome and, as a result, I have recommended your product to a number of other people. So, perhaps you were having a bad day ... and perhaps I am misunderstanding what you meant.

I guess you have misunderstood my reply (I guess you were having a bad day to interpret it in a bad way). I ment no offence. I thought you might have missed the argument I've supplied, which was: The attribute is placed on properties mapped on relations because otherwise they will end up as columns inside the grid, and that maybe you want to read it again.

A final remark: As Frans have explained it, we have the design that we think fits the most common scenarioes. But at the same time we ship the templates and the source code, in case our common scenarioes based design, doesn't fit you. So you are mostly welcomed to modify whatever you want, and in this case, you may just modify the Browsable attribute in the templates (as you have figured it already), and that's it.

Good Luck.

colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 19-Sep-2007 23:12:57   

Thank you for such in depth replies. I'd only like to ask one more question ... please?

Right back at the beginning of all this I explained that the mechanism I am using to display the field from a related object works perfectly using the standard asp GridView. That is, I can use the Eval method to display the related objects field like this:

<%# Eval("ProductManager.Name") %>

This already works and I have used it extensively. The ProductManager property is not displayed in the Visual Studio designer in the list of columns for this grid but it can be navigated to and used to display internal fields at runtime.

So, clearly, all the problems that you talk about above have been solved or do not apply when using the asp:GridView. Obviously the GridView is able to find this property at runtime but filters it from the list at design time.

So, my question all along has been "Why is this different when using the DevExpress GridView?"

When using that grid the property was not visible at design time OR runtime.

For the DevExpress grid I had to modify the Browsable attribute .... but for the standard asp grid I did not.

Your frustration at working around the asp "standards" comes through very clearly and I sympathise with your problems. You guys have done an awesome job under very difficult circumstances ....

I am definitely NOT pointing fingers but something is different here. Can you please think about what that might be?

Thank you for your patience.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 20-Sep-2007 12:15:04   

colincsb wrote:

Thank you for such in depth replies. I'd only like to ask one more question ... please?

Ok simple_smile

Right back at the beginning of all this I explained that the mechanism I am using to display the field from a related object works perfectly using the standard asp GridView. That is, I can use the Eval method to display the related objects field like this:

<%# Eval("ProductManager.Name") %>

This already works and I have used it extensively. The ProductManager property is not displayed in the Visual Studio designer in the list of columns for this grid but it can be navigated to and used to display internal fields at runtime.

True. The design time stuff is displaying only entity fields and your own custom properties you added to the entity and which aren't marked with browsable(false).

So, clearly, all the problems that you talk about above have been solved or do not apply when using the asp:GridView. Obviously the GridView is able to find this property at runtime but filters it from the list at design time.

No, that's not how it's done. simple_smile Eval() at runtime performs reflection on the object to render. This means that there is a live object it works on, and it performs a hard reflection on the property, THEN navigates. So there's no ITypedList call whatsoever, it does a hard reflection on the property. In SelfServicing, you see this in action where it will reflect the property and perform a 'get' on it, which will trigger lazy loading .. per row. So it will trigger query creation per row, per property. (you can avoid lazy loading by fetching the related data in a prefetch path, but the reflection stays.)

Design time... that's a total different approach: there's no data. There are no objects to reflect on. To be able to retrieve info about the objects to view at runtime the grid asks via ITypedList what the properties are. These are then returned by the datasourcecontrol.

So, my question all along has been "Why is this different when using the DevExpress GridView?"

When using that grid the property was not visible at design time OR runtime. For the DevExpress grid I had to modify the Browsable attribute .... but for the standard asp grid I did not.

That's because the DevExpress grid plays nice all the way simple_smile . At runtime this happens (in all grids/databinding scenario's) Grid calls ExecuteSelect on the datasourcecontrol. Datasource control returns an EntityView(2) object. This object implements ITypedList. If you for example use Infragistics grid, you'll get ALL properties in your grid, because they don't look at ITypedList on the object to view (the EntityView and its contents). This sucks, because it's a pain to remove all the properties you don't need. DevExpress knows this and among other control vendors knows how to do databinding properly and calls ITypedList.GetItemProperties on the entityview(2) object it has to bind to, to determine which columns to produce. THESE properties are then used by the grid. There are NO OTHER properties reflected from the objects to render. The main reason is that if they would do so, they would trigger lazy loading perhaps on the object bound. It also would be a problem what to do if the datasource is empty... To be able to determine which columns to show, you still simply ask ITypedList.GetItemProperties and the properties are reported, even with no data. If you would do AddNew() and then reflect over it, you'll probably creating a problem. (this is how the winforms datagridview does it btw, not great).

So this isn't really solvable unless devexpress (and others) will drop support for ITypedList. Though I'm glad they DO support it, because it's the best thing to do. The only drawback is: the ITypedList implementation should be tweakable perhaps and that's precisely what's a bit of a problem simple_smile .

Your frustration at working around the asp "standards" comes through very clearly and I sympathise with your problems. You guys have done an awesome job under very difficult circumstances ....

I am definitely NOT pointing fingers but something is different here. Can you please think about what that might be? Thank you for your patience.

I hope I've illustrated correctly what the difference is. simple_smile .

Unfortunately, I think there's no real solution here, besides removing the Browsable(false) attribute from the field mapped onto relation property generated into the code using a custom template, or using fields mapped onto related fields.

Frans Bouma | Lead developer LLBLGen Pro
colincsb
User
Posts: 18
Joined: 01-Nov-2006
# Posted on: 20-Sep-2007 12:39:31   

Thanks for taking the time to explain all that Otis ... I have managed to follow most of it :-)

Guess I'll just continue with this workaround and hope that things improve (interface-wise) in the future.

worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 09-Nov-2007 06:56:22   

Wouldn't the path of least resistance be just to tweak the templates? (I mean u colin).

I also have the same issue in a loosely related scenario.

.\Solutions Design\LLBLGen Pro v2.0\Templates\SharedTemplates\Net2.x\C#\entityIncludeAdapter.template

line 578 change: [Browsable(false)] to: //[Browsable(false)]

Note i'm using June 15th, 2007 build v2.0 so line # may be different.

Remember LLBLGen is highly hackable. If it don't work, make it work!

Took me about 4 minutes to find the right spot to change and now it's all happy rays of sunshine, with rainbows, carebears and leprechauns and stuff. smile

Edit: oops ur using self servicing so my edit prolly won't be right for u. But my argument stands, just find the file urself wink