Binding Hierarchical RadGrid with Telerik OpenAccess ORM

by OpenAccess ORM Team | Comments 5

It is quite often that different customers eventually face the need to use a master-detail hierarchical representation of their data. However most customers are not aware that this is extremely easily achievable using Telerik OpenAccess ORM together with our RadGrid. Furthermore it is achieved without writing ANY code in the code behind file of your project.

Now let’s get to the job!

What will be needed is just one RadGrid and two OpenAccessDataSource controls. The two data source controls will be used to query data from the master and detail tables. In our case we used the Company and Employee tables(one company has many employees).

    public partial class Company
   
{
       
//The 'no-args' constructor required by OpenAccess. 
        public Company()
       
{
       
}

       
[Telerik.OpenAccess.FieldAlias("companyId")]
       
public int CompanyId
       
{
           
get { return companyId; }
           
set { this.companyId = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("address")]
       
public string Address
       
{
           
get { return address; }
           
set { this.address = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("name")]
       
public string Name
       
{
           
get { return name; }
           
set { this.name = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("employees")]
       
public IList<Employee> Employees
       
{
           
get { return employees; }
       
}


   
}
public partial class Employee
   
{
       
//The 'no-args' constructor required by OpenAccess. 
        public Employee()
       
{
       
}

       
[Telerik.OpenAccess.FieldAlias("employeeId")]
       
public int EmployeeId
       
{
           
get { return employeeId; }
           
set { this.employeeId = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("firstName")]
       
public string FirstName
       
{
           
get { return firstName; }
           
set { this.firstName = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("lastName")]
       
public string LastName
       
{
           
get { return lastName; }
           
set { this.lastName = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("phone")]
       
public string Phone
       
{
           
get { return phone; }
           
set { this.phone = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("ssn")]
       
public string Ssn
       
{
           
get { return ssn; }
           
set { this.ssn = value; }
       
}

       
[Telerik.OpenAccess.FieldAlias("company")]
       
public Company Company
       
{
           
get { return company; }
           
set { this.company = value; }
       
}
       
public int EmployeeCompanyId
       
{
           
get { return company.CompanyId; }            
       
}


   
}
Notice the EmployeeCompanyId property. We will discuss it in a minute as it will make much more sense after we look at the definition of the grid. But first let’s see the definition of the two data source controls:
  <telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
            ObjectContextProvider
="Model.ObjectScopeProvider1, Model" 
            TypeName
="Model.Company">
       
</telerik:OpenAccessDataSource>
   
</div>
   
<telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider
="Model.ObjectScopeProvider1, Model" 
        TypeName
="Model.Employee" Where="Company.CompanyId == @Company.CompanyId">
       
<WhereParameters>
           
<asp:SessionParameter Name="Company.CompanyId" SessionField="CompanyId" />
        </
WhereParameters>
   
</telerik:OpenAccessDataSource>

As you can see the first one queries all objects from the Company table. The second one returns only those employee that match the selected company id. This id is obtained with a session parameter.
Now let’s define our grid. First we will need to bind the MasterTableView of the grid to the first data source as we want all the company objects to be displayed there. Then we need to bind the second data source to the details table of the grid in order to be displayed for each company. Here is how it is done:

<telerik:RadGrid ID="RadGrid1" runat="server" 
            DataSourceID
="OpenAccessDataSource1" AutoGenerateEditColumn="True" 
            GridLines
="None">
<HeaderContextMenu>
<CollapseAnimation Type="OutQuint" Duration="200"></CollapseAnimation>
</HeaderContextMenu>

<MasterTableView AutoGenerateColumns="False" DataKeyNames="CompanyId" 
                DataSourceID
="OpenAccessDataSource1" AllowAutomaticUpdates="true">    
   
<DetailTables>
       
<telerik:GridTableView runat="server" DataSourceID="OpenAccessDataSource2" DataKeyNames="EmployeeId,EmployeeCompanyId" AllowAutomaticUpdates="true">
       
<ParentTableRelation>
       
<telerik:GridRelationFields DetailKeyField="Company.CompanyId" MasterKeyField="CompanyId" />
        </
ParentTableRelation>
       
</telerik:GridTableView>
   
</DetailTables>
<RowIndicatorColumn>
<HeaderStyle Width="20px"></HeaderStyle>
</RowIndicatorColumn>

<ExpandCollapseColumn Visible="True">
<HeaderStyle Width="20px"></HeaderStyle>
</ExpandCollapseColumn>
   
<Columns>
       
<telerik:GridBoundColumn DataField="CompanyId" DataType="System.Int32" 
            HeaderText
="CompanyId" ReadOnly="True" SortExpression="CompanyId" 
            UniqueName
="CompanyId">
       
</telerik:GridBoundColumn>
       
<telerik:GridBoundColumn DataField="Address" HeaderText="Address" 
            SortExpression
="Address" UniqueName="Address">
       
</telerik:GridBoundColumn>
       
<telerik:GridBoundColumn DataField="Name" HeaderText="Name" 
            SortExpression
="Name" UniqueName="Name">
       
</telerik:GridBoundColumn>
   
</Columns>
</MasterTableView>

<FilterMenu>
<CollapseAnimation Type="OutQuint" Duration="200"></CollapseAnimation>
</FilterMenu>
       
</telerik:RadGrid>
The only tricky part here is that where you specify which fields will be the data keys you can’t really use Company.CompanyID. This is where our EmployeeCompanyId kicks in. Using this property we will “help” the grid to successfully find the correct value required during update. Now you can just start using the grid. Note that if you would like to delete data you will have to enable Cascading delete for the Employees collection in the company class and everything will work out of the box.

We have defined some animations for expanding and collapsing as well, and now RadGrid looks quite “slick”.

I hope you enjoyed this example as much as I did writing it.

5 Comments

rentoc

Invalid typecast "Telerik.OpenAccess.OpenAccessDataSource" to type "System.Web.UI.DataSourceControl". 

What is wrong?

Jonathan
I keep getting the following error when I try to build a hierarchical grid:

Telerik.OpenAccess.Exceptions.QueryException: line 1:78: unexpected char: '@'
Original Query: DEFINE EXTENT xt FOR SMC.Data.Entity; SELECT * FROM xt AS this WHERE DrugID == @drugID


No matter how I define the OA datasources, I always get this error. Any ideas,
Regards,
Jonathan
rentoc

What about the error:

Invalid typecast "Telerik.OpenAccess.OpenAccessDataSource" to type "System.Web.UI.DataSourceControl".

Do you will fix this bug?

Tobias op den Brouw
I have tried something similar, but run into similar problems as earlier comments (which you have not replied to in this location).

Some oddities:

1. the second OpenAccessDataSource has a parameter set to a session object. Is this correct? Does that implicate that the mastertable is setting this session object when the 'expand' triangle icon is clicked on the master grid? Setting this parameter to the Selectedvalue of the grid gives me an error similar to Jonathan's 30 nov post.

2. OpenAccess has default ID column names set to 'ID' (when using the visual designer to create entities). This is what I am using. Will your example still work when both the master and the detail table have their (primary key) ID fields both named 'ID'?

Tx much in advance,
Tobias

ntprabhu
I have two OpenAccessDataSource in page, One DataSource is to bind the RadGrid Control and another one is for RadCombo, But I'm Getting the same error 

"

No class found for extent "xt".
Original Query: DEFINE EXTENT xt FOR ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD; SELECT * FROM xt AS this

"
telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server"  
ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL"
ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
TypeName="ClassLibrary1.DP_UREMOVAL">
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource>
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource>
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource>
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource>
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource>
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource>
<telerik:OpenAccessDataSource ID="OpenAccessDataSource1" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.DP_UREMOVAL">
    </telerik:OpenAccessDataSource>

     <telerik:OpenAccessDataSource ID="OpenAccessDataSource2" runat="server" 
        ObjectContextProvider="ClassLibrary1.CBMEntityDiagrams, ClassLibrary1" 
        TypeName="ClassLibrary1.NW_U_T_FLEET_REMVL_TREND_HEAD">
    </telerik:OpenAccessDataSource

Is anything I miss here, I'm very now to this one please any one help this.... that will be really helpful...

Comments

  1.    
      
      
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)
Read more articles by OpenAccess ORM Team - or - read latest articles in Developer Tools