This is a migrated thread and some comments may be shown as answers.

Binding Assumes Wrong Object Type

15 Answers 230 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Shane
Top achievements
Rank 1
Shane asked on 01 Dec 2010, 05:56 PM
We are using the RadGrid control to retrieve User objects from a repository that uses NHibernate to retrieve the objects. I am using an object data source defined as:
<asp:ObjectDataSource ID="UsersData" runat="server" SelectMethod="GetAll" DataObjectTypeName="TestingApp.Lib.Domain.User" TypeName="TestingApp.Lib.Repositories.UserRepository">
</asp:ObjectDataSource>

The method signature for GetAll is as follows:
public IEnumerable<User> GetAll();

With NHibernate, some Users are actually AdminUsers which extends User. It seems the repository is currently returning an AdminUser object first, and the control seems to be assuming then that the rest of the objects will be AdminUser rather than User. This causes the following exception to be thrown:
"Unable to cast object of type 'TestingApp.Lib.Domain.User' to type 'TestingApp.Lib.Domain.AdminUser'."

Is there a way to force the control to assume that data bound objects are User rather than AdminUser? Thanks!

15 Answers, 1 is accepted

Sort by
0
Veli
Telerik team
answered on 06 Dec 2010, 01:13 PM
Hello Shane,

Can you show us your RadGrid definition and any related code? RadGrid may refer to the first object in the collection to infer the data type of the collection, but in this case, you haev specified a generic collection, so RadGrid should know the type from the generic parameter. The exception you are getting is thrown when RadGrid cannot infer the type of the collection from the collection itself and needs to look at the  type of the first element in the collection. Can you verify the DataSource passed to RadGrid is of type IEnumerable<User>, i.e. it is generic?

Veli
the Telerik team
Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Shane
Top achievements
Rank 1
answered on 07 Dec 2010, 06:18 PM
It appears the issue is related to using IEnumerable<User>/IQueryable<User>. When I change the output type to List<User>, it works fine. Obviously I don't want to do that as it'll cause the entire table to be loaded into memory without filtering before the query. Any suggestions? :)
0
Veli
Telerik team
answered on 08 Dec 2010, 09:15 AM
Hi Shane,

I created a small test page to try this out. What I'm getting: IEnumerable<User>, IQueryable<User> and List<User> all have RadGrid properly bind to instances of the User type and its subtype. Binding to ArrayList however throws an exception. Attaching the test page.

Veli
the Telerik team
Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Shane
Top achievements
Rank 1
answered on 08 Feb 2011, 09:32 PM
Thanks for the response Veli. My apologies for this lingering. I did verify that the sample you provided worked as described. While I haven't found the exact cause, I did narrow it down a little.

You can reproduce this when you are binding to an IQueryable<User> response from NHibernate.Linq<User>() request as follows:
RadGrid1.DataSource = (from u in Session.Linq<User>()
                 select u).AsQueryable<User>();

This results in the following error:
[InvalidCastException: Unable to cast object of type 'UserProxy911331a3e8e141849ebd93abf294e718' to type 'TestingApp.Lib.Domain.AdminUser'.]
   Telerik.Web.UI.GetEnumerator>d__0.MoveNext() +137
   System.Linq.Enumerable.Count(IEnumerable`1 source) +225
   lambda_method(Closure ) +97
   System.Linq.EnumerableExecutor`1.Execute() +94
   System.Linq.EnumerableExecutor`1.ExecuteBoxed() +23
   System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute(Expression expression) +94
   Telerik.Web.UI.GridDynamicQueryable.Count(IQueryable source) +143
   Telerik.Web.UI.GridDataTableFromEnumerable.FillData35() +235
   Telerik.Web.UI.GridDataTableFromEnumerable.FillData() +779
   Telerik.Web.UI.GridResolveEnumerable.Initialize() +35
   Telerik.Web.UI.GridResolveEnumerable.EnsureInitialized() +24
   Telerik.Web.UI.GridEnumerableFromDataView..ctor(GridTableView owner, IEnumerable enumerable, Boolean CaseSensitive, Boolean autoGenerateColumns, GridColumnCollection presentColumns, String[] additionalField, Boolean retrieveAllFields) +203
   Telerik.Web.UI.GridDataSourceHelper.CreateGridEnumerable(GridTableView owner, IEnumerable enumerable, Boolean caseSensitive, Boolean autoGenerateColumns, GridColumnCollection presentColumns, String[] additionalField, Boolean retrieveAllFields) +119
   Telerik.Web.UI.GridDataSourceHelper.GetResolvedDataSource(GridTableView owner, Object dataSource, String dataMember, Boolean caseSensitive, Boolean autoGenerateColumns, GridColumnCollection presentColumns, String[] additionalField, Boolean retrieveAllFields) +389
   Telerik.Web.UI.GridTableView.get_ResolvedDataSource() +150
   Telerik.Web.UI.GridTableView.CreateChildControls(IEnumerable dataSource, Boolean useDataSource) +33
   System.Web.UI.WebControls.CompositeDataBoundControl.PerformDataBinding(IEnumerable data) +66
   System.Web.UI.WebControls.DataBoundControl.OnDataSourceViewSelectCallback(IEnumerable data) +128
   System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +33
   System.Web.UI.WebControls.DataBoundControl.PerformSelect() +143
   Telerik.Web.UI.GridTableView.PerformSelect() +16
   System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +74
   Telerik.Web.UI.GridTableView.DataBind() +259
   Telerik.Web.UI.RadGrid.DataBind() +87
   Telerik.Web.UI.RadGrid.AutoDataBind(GridRebindReason rebindReason) +2337
   Telerik.Web.UI.RadGrid.OnLoad(EventArgs e) +132
   System.Web.UI.Control.LoadRecursive() +74
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207

However, if I set the DataSource to the results of the following method, it works fine:
public IEnumerable<User> GetUsersIEnumerable()
{
    foreach (var u in (from u in Session.Linq<User>()
                 select u).AsQueryable<User>())
        yield return u;
}

If you have any suggestions, I am all ears at this point. Thanks!
0
Veli
Telerik team
answered on 09 Feb 2011, 01:05 PM
Hi Shane,

It seems the Linq to NHibernate query is returning an IQueryable containing proxy objects that cannot be cast to a derived AdminUser type. While the implementation of the NH Linq provider is beyond our scope of research, it is curious that a second iteration on the resulting IQueryable yields objects of a valid type. If you can send us some test project we can debug locally, we may be able to further investigate this issue.

Veli
the Telerik team
Browse the vast support resources we have to jump start your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Shane
Top achievements
Rank 1
answered on 09 Feb 2011, 05:14 PM
Veli,

Do you have any idea why Telerik is trying to cast to AdminUser instead of User? I do know that the first result is of the type AdminUser. But since the output type of the method is User, it seems odd that it would try to cast subsequent User objects to AdminUser.

I've tried it with and without RetrieveDataTypeFromFirstItem set to false in the MasterTableView.

I'm going to spend some time later today putting together a test project for you.

Thanks

Shane
0
Shane
Top achievements
Rank 1
answered on 11 Feb 2011, 11:15 PM
I've put together a quick project that reproduces the error. Let me know if it works for you:

http://www.mediafire.com/?kq4loge4ewcergu

Thanks!
0
Veli
Telerik team
answered on 15 Feb 2011, 10:16 AM
Hi Shane,

It seems the database is missing from the App_Data folder. The solution is expecting to find a database file (Database1.mdf), but it is not in the folder.

Veli
the Telerik team
Browse the vast support resources we have to jump start your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Shane
Top achievements
Rank 1
answered on 15 Feb 2011, 03:31 PM
Not 100% sure what happened, but when I zipped it up again, I verified that it included the database this time.

http://www.mediafire.com/?xw0ckzu5bt2wkq6

Thanks for your time!
0
Veli
Telerik team
answered on 16 Feb 2011, 03:16 PM
I got it up and running OK this time. 10x. And I am getting the exception, although the exception message says that an instance of "User" cannot be cast to an "AdminUser", not some proxy object created by NHibernate. Anyway, researching further on, it turns out that NHibernate behaves in some weird way. Particularly, the NHibernate query returns 2 different enumerators for the following 2 scenarios:

1. Cast it IEnumerable and call GetEnumerator()
2. Call GetEnumerator() directly as a method of the dynamic Linq query.

The result:

IEnumerable en = GetQueryable();
//enumerator type is System.Collections.ArrayList.ArrayListEnumeratorSimple
var enumerator1 = en.GetEnumerator();
//enumerator type is NHibernate.Linq.CriteriaResultReader
var enumerator2 = GetQueryable().GetEnumerator();

Due to the strange enumerator behavior in NHibernate, RadGrid cannot properly infer the type of the data objects in the collection. It then falls back to assuming the first data item type to be the type of all the items in the collection. The exception is the result of a failure to cast items of a base type to items in a derived type. Even though you have a generic Linq query result from GetQueryable(), RadGrid cannot identify this.

The workaround: Call ToList() to execute the query and return the actual data objects in a collection:

protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
{
    RadGrid1.DataSource = GetQueryable().ToList();      // Works
    //RadGrid1.DataSource = GetEnumerable().Reverse();  // Works
}

Now RadGrid's data source is a static list of data objects returned in a generic IEnumerable<User> collection. RadGrid can read the data object type from the generic type argument and you are getting the public properties of the User class bound to RadGrid.


Veli
the Telerik team
Browse the vast support resources we have to jump start your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Shane
Top achievements
Rank 1
answered on 16 Feb 2011, 04:35 PM
Veli,

Thanks for the explanation. Is there a way to tell the grid what type of object it should assume rather than have it attempt to infer it from the first in the collection?

I'd like to take advantage of the IQueryable function for sorting/filtering.
0
Veli
Telerik team
answered on 17 Feb 2011, 01:19 PM
You cannot specify the type of the data objects explicitly. On the other hand, in .NET 3.5 and 4.0 RadGrid automatically takes advantage of the LINQ engine using IQueryable for data operations. You do not need to explicitly specify an IQueryable query as its data source.

Veli
the Telerik team
0
Andy
Top achievements
Rank 1
answered on 09 Dec 2013, 09:18 PM
I have a similar issue.  I have a collection of objects that are the same base type but some are sub-typed.  An error is thrown when databinding, the grid is trying to cast into the incorrect sub-types.  Is there a way to specify what type to use for the objects in the collection?  I don't need to access any of the properties unique to the subtypes.
0
Radoslav
Telerik team
answered on 12 Dec 2013, 09:41 AM
Hello Andy,

Unfortunately as my colleague Veli said you cannot specify the type of the data objects explicitly.  The only way to avoid the exception is to bind the grid to collection of the base type. I am sending you a simple example which demonstrates that. Please check it out and let me know if it helps you.

Looking forward for your reply.

Regards,
Radoslav
Telerik
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to the blog feed now.
0
Andy
Top achievements
Rank 1
answered on 13 Dec 2013, 12:27 PM
Thanks for the example.  I was able to convert my collection to a List<MyBaseClass> and bind it to the grid with a various subtypes in the list.
Tags
Grid
Asked by
Shane
Top achievements
Rank 1
Answers by
Veli
Telerik team
Shane
Top achievements
Rank 1
Andy
Top achievements
Rank 1
Radoslav
Telerik team
Share this question
or