WebForms Databinding to Grand Child Collection

Posts   
 
    
KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 21-Nov-2006 06:37:43   

I have the following schema:

Employee - 1 to 1 - ContactInformation ContactInformation - 1 to * - Telephone

I want inside of a single grid Employee Info, Contact Info and in the last column a repeater bound to the list of Telephone numbers.

I'd like to use simple databinding and Frans has an example online showing how to bind a list of orders like this to a customer, my problem is i want to bind to a child collection of Contact Information and whenever I try to access the list using Eval("TelephoneCollection") I get an error that the property doesn't exist. Here's some code.


IPrefetchPath path = new PrefetchPath((int)EntityType.CompanyOfficeEntity);
path.Add(CompanyOfficeEntity.PrefetchPathContactInformation).SubPath.Add( 
          ContactInformationEntity.PrefetchPathTelephoneCollectionViaContactInformationTelephone);
                            
llblCompanyOffice.PrefetchPathToUse = path;


in my aspx file:
<asp:Repeater ID="rptPhones" runat="server" DataSource='<%# Eval("TelephoneCollectionViaContactInformationTelephone") %>'>
                            <ItemTemplate>
                                <asp:Label ID="Label1" runat="server" Text='<%# RELink.UI.Process.Telephone.formatTelephone(Eval("TelephoneNumber").ToString(), Eval("Extension").ToString()) %>' /> - 
                                <asp:Label ID="Label2" runat="server" Text='<%# Eval("TelephoneType") %>' /><br />  
                            </ItemTemplate>
                            </asp:Repeater>


The error i get is:

DataBinding: 'ALTA.LLBL.EntityClasses.CompanyOfficeEntity' does not contain a property with the name 'TelephoneCollectionViaContactInformationTelephone'.

Thanks.

-Kas

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 21-Nov-2006 09:18:34   

You access in your code ContactInformationEntity.PrefetchPathTelephoneCollectionViaContactInformationTelephone in the prefetch path. The 'Via' suggests you refer to a field mapped onto an m:n relation. Did you have this setup as an m:n relation before? If so, did you make sure the generated code you work with in your application is recent, i.e. you did generate the code after you refreshed the catalog so the contactinformation 1:n Telephone relation was present in the generated code?

With these kind of errors, first thing you should do is build the generated code project to see if that compiles. When that's the case, open ContactInformationEntityBase (assuming you're using 2-class scenario) and check if the property TelephoneCollection is there and also PrefetchPathTelephoneCollectionViaContactInformationTelephone

Frans Bouma | Lead developer LLBLGen Pro
KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 22-Nov-2006 00:05:06   

Everything builds just fine and if i write a static method in a helper class such the following I can retrieve and bind the list but the problem is I have to write static methods and bind to the method for each related collection I want to retrieve. I'm sure theres a better way to do this. Please give me a code example of how I would bind to the TelephoneCollection directly without the need for this extra UI.Process method.



public static TelephoneCollection getTelephones(int ContactInformationId)
        {
            ContactInformationEntity con = new ContactInformationEntity(ContactInformationId);
            if (! con.IsNew)
            {
                return con.TelephoneCollectionViaContactInformationTelephone;
            }
            return new TelephoneCollection();
            


-Kas

bclubb
User
Posts: 934
Joined: 12-Feb-2004
# Posted on: 22-Nov-2006 02:22:05   

You say the relationship is 1:1 and then 1:n

What happens if you define this as your prefetch?


IPrefetchPath path = new PrefetchPath((int)EntityType.CompanyOfficeEntity);
path.Add(CompanyOfficeEntity.PrefetchPathContactInformation).SubPath.Add(ContactInformationEntity.PrefetchPathTelephone);

KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 22-Nov-2006 07:48:46   

It's 1:m (1 being ContactInformation and "m" being Telephone) There is no prefetch path named PrefetchPathTelephone. Code doesn't compile. I have a PrefetchPathTelephoneCollectionViaContactInformationTelephone, but again when I set this how do I set the aspx code's databinding expression to understand. I tried

Eval("TelephoneCollectionViaContactInformationTelephone")

but that throws an error

thanks

-Kas

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 22-Nov-2006 08:35:42   

KastroNYC wrote:

It's 1:m (1 being ContactInformation and "m" being Telephone) There is no prefetch path named PrefetchPathTelephone. Code doesn't compile. I have a PrefetchPathTelephoneCollectionViaContactInformationTelephone, but again when I set this how do I set the aspx code's databinding expression to understand. I tried

Eval("TelephoneCollectionViaContactInformationTelephone")

but that throws an error

thanks -Kas

Something is out of sync, as PrefetchPathTelephoneCollectionViaContactInformationTelephone is a field name constructed with the template for names for M:N relations, where ContactInformationTelephone is the intermediate entity. As you state the relation is 1:n, you should have a TelephoneCollection field in the Contact entity in the llblgen pro designer. If that's the case, the generated code isn't in sync with the designer's entity definitions.

Could you please attach to a post in this thread your .lgp file? the max. attachment size is 256KB, if your .lgp file is bigger, please email it to support AT llblgen.com or post a thread in the secure helpdesk forum where you can attach 1MB files to messages.

Your code should be OK with this exception: Eval("TelephoneCollectionViaContactInformationTelephone") should be Eval("TelephoneCollection")

however that gives an error as you stated, so the cause of that error has to be solved now.

Frans Bouma | Lead developer LLBLGen Pro
KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 23-Nov-2006 04:51:28   

Sorry about that, it is an M:N through ContactInformation Telephone. I've tried:

IPrefetchPath path = new PrefetchPath((int)EntityType.CompanyOfficeEntity);
        path.Add(CompanyOfficeEntity.PrefetchPathContactInformation).SubPath.Add( ContactInformationEntity.PrefetchPathContactInformationTelephone)
            .SubPath.Add(ContactInformationTelephoneEntity.PrefetchPathTelephone);

then binding with

Eval("TelephoneCollection")

and

IPrefetchPath path = new PrefetchPath((int)EntityType.CompanyOfficeEntity);
        path.Add(CompanyOfficeEntity.PrefetchPathContactInformation).SubPath.Add( ContactInformationEntity.PrefetchPathTelephoneCollectionViaContactInformationTelephone);

and binding

Eval("TelephoneCollectionViaContactInformationTelephone");

neither works.

Is there a way to bind this declaratively or do I need a static method in a helper class somewhere?

Thanks.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 23-Nov-2006 10:10:19   

KastroNYC wrote:

Sorry about that, it is an M:N through ContactInformation Telephone.

THis is a major difference.

I've tried:

IPrefetchPath path = new PrefetchPath((int)EntityType.CompanyOfficeEntity);
        path.Add(CompanyOfficeEntity.PrefetchPathContactInformation).SubPath.Add( ContactInformationEntity.PrefetchPathContactInformationTelephone)
            .SubPath.Add(ContactInformationTelephoneEntity.PrefetchPathTelephone);

then binding with

Eval("TelephoneCollection")

and

IPrefetchPath path = new PrefetchPath((int)EntityType.CompanyOfficeEntity);
        path.Add(CompanyOfficeEntity.PrefetchPathContactInformation).SubPath.Add( ContactInformationEntity.PrefetchPathTelephoneCollectionViaContactInformationTelephone);

and binding

Eval("TelephoneCollectionViaContactInformationTelephone");

neither works.

Is there a way to bind this declaratively or do I need a static method in a helper class somewhere?

Thanks.

Please understand this first: in the designer you've Fields mapped onto relations below every entity. These fields will become properties which will return one instance (in the case of fields mapped onto m:1 and 1:1 relations) or a collection (in the case of 1:n and m:n).

So if your field in the designer is called TelephoneCollectionViaContactInformationTelephone, then you'll never have a property in the entity called TelephoneCollection, but a property which is called TelephoneCollectionViaContactInformationTelephone.

With m:n relations there's something else: these are hidden by default because the designer often finds a lot of m:n relations and people often don't need them, so this leads to a lot of relations, code etc.. So please take these steps: - in the designer, in the Contact entity, do you have a field mapped onto a relation called TelephoneCollectionViaContactInformationTelephone ? - if so, is it hidden? This is visible through the dimmed icon in front of it. - if it's hidden, it won't show up in your code. If it's hidden, it's likely the relation this field is mapped on is also hidden. Click open the relations node and please check if the m:n relation contact - telephone is indeed hidden (this is shown by the dimmed icon in front of it).

If it's hidden, simply right click it and select toggle hide BOTH sides. Also do that with the field TelephoneCollectionViaContactInformationTelephone. Then regenerate the code.

Frans Bouma | Lead developer LLBLGen Pro
KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 23-Nov-2006 21:56:28   

I checked it out as you instructed and none of my Fields Mapped On Relations for the ContactInformation entity are hidden. I'm using this property TelephoneCollectionViaContactInformation from within my static helper method now.

The structure again is:

ContactInformation 1 - m with [ContactInformation Telephone] [ContactInformation Telephone] (intermediary) 1 - 1 ContactInformation - Telephone Telephone - 1 - m Telephone - [Contactinformation Telephone]

so do i need to stick to the static methods in order to get this to work? thanks.

-kasi

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 23-Nov-2006 22:07:54   

Could you attach your .lgp file to a message, please, that's probably a lot easier to explain things. If you don't want others to see the .lgp file, please open a new thread in the secure helpdesk forum. The thing is that it's unclear to me how the relation structure looks like.

Also, the ContactInformationEntityBase class, does it have a property called TelephoneCollectionViaContactInformation ?

Frans Bouma | Lead developer LLBLGen Pro
KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 23-Nov-2006 22:40:25   

ContactInformation does have a TelephoneCollectionViaContactInformation property. Here is the code from ContactInformationEntity.cs

(im using self-servicing)



/// <summary> Retrieves all related entities of type 'TelephoneEntity' using a relation of type 'm:n'.</summary>
        /// <remarks>This property is added for databinding conveniance, however it is recommeded to use the method 'GetMultiTelephoneCollectionViaContactInformationTelephone()', because 
        /// this property is rather expensive and a method tells the user to cache the result when it has to be used more than once in the same scope.</remarks>
        public virtual ALTA.LLBL.CollectionClasses.TelephoneCollection TelephoneCollectionViaContactInformationTelephone
        {
            get { return GetMultiTelephoneCollectionViaContactInformationTelephone(false); }
        }



i uploaded my file to the help desk forum.

thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 24-Nov-2006 10:13:36   

Thanks. I now see what's wrong. In your form, you bind CompanyOffice entities to the grid. This means that inside the grid, the fields and fieldsmapped onto relations etc. of CompanyOffice (all fields) are visible directly using Eval("Fieldname").

TelephoneCollectionViaContactInformationTelephone isn't a field of CompanyOffice, it's a field of ContactInformation. So TelephoneCollectionViaContactInformationTelephone isn't directly accessable, though ContactInformation is. I hope this is clear, as it's fundamental to understand the next step.

To access TelephoneCollectionViaContactInformationTelephone, you're actually doing: this.ContactInformation.TelephoneCollectionViaContactInformationTelephone.

In my example, I visualize each customer's orders. The orders are directly accessable as they're part of the customers bound to the grid.

So your original line:


<asp:Repeater ID="rptPhones" runat="server" DataSource='<%# Eval("TelephoneCollectionViaContactInformationTelephone") %>'>

has to become:


<asp:Repeater ID="rptPhones" runat="server" DataSource='<%# Eval("ContactInformation.TelephoneCollectionViaContactInformationTelephone") %>'>

This is more ASP.NET related though.

Frans Bouma | Lead developer LLBLGen Pro
KastroNYC
User
Posts: 96
Joined: 23-Jan-2006
# Posted on: 24-Nov-2006 17:40:50   

Sorry for the trouble and I greatly appreciate the help. This is awesome. I'm so glad to get rid of those stupid static methods.

-Kas