0

I have a select method for ObjectDataSource:

    public static IEnumerable<Model.Domain.Theme> Select()
    {
        var cycleRepo = new RbaCycleRepository(Global.sessionFactory.GetCurrentSession());
        RbaCycle lacOpenCycle = cycleRepo.FindLacOpenCycle();
        if (lacOpenCycle != null)
        {
            var themeRepo = new ThemeRepository(Global.sessionFactory.GetCurrentSession());
            var result = themeRepo.FindAll(new ThemesForCycle(lacOpenCycle).GetQuery());
            return result;
        }
        return Enumerable.Empty<Model.Domain.Theme>();
    }

And here is the scenario:

  • I click on the button, some actions are performed and as a result I end up with a few proxy Theme objects in 1st level cache - which is fine.
  • Select() method is called and it returns result. The result can contain only Theme objects or a mix of Theme and NHibernate Castle Proxy (for instance). This is a trace from watch window:

{Castle.Proxies.ThemeProxy} Model.Domain.Theme {Castle.Proxies.ThemeProxy} {Model.Domain.Theme} Model.Domain.Theme

  • If the first object in the result collection is actual Theme object, then binding of the whole collection succeedes. But if first element in collection is Proxy object, then I end up with exception:

Unhandled exception: System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.Reflection.TargetInvocationException: Property accessor 'Title' on object 'CIPNet.Model.Domain.Theme' threw the following exception:'Object does not match target type.' ---> System.Reflection.TargetException: Object does not match target type.

EDIT: This is FindAll implementation:

    public IList<T> FindAll(QueryOver<T, T> query)
    {
        return query.GetExecutableQueryOver(session).List();
    }
dragonfly
  • 17,407
  • 30
  • 110
  • 219

2 Answers2

0

Looks like ObjectDataSource is using the first element of the collection to figure out the columns for data source. Since it's using reflection, NHibernate / Castle DynamicProxy doesn't have a chance to unproxy the object. You'll probably need to do that manually.

Identifying NHibernate proxy classes
NHibernate: Get concrete type of referenced abstract entity

Also, if your FindAll method is returning IQueriable or IEnumerable, try to call .ToList() or .ToArray() on result, to force the query execution. You might not need to unproxy manually:

var result = 
    themeRepo.FindAll(new ThemesForCycle(lacOpenCycle).GetQuery()).ToList();
Community
  • 1
  • 1
Miroslav Popovic
  • 12,100
  • 2
  • 35
  • 47
0

This is the temp solution I came up with. It works, I just make sure that list which is binded to control has first object that is not proxy:

    public static IList<T> ToProxySafeList<T>(this IList<T> list)
        where T: class
    {
        if (list.Count == 0) return list;

        var proxy = list[0] as INHibernateProxy;
        if (proxy != null)
        {
            list[0] = proxy.HibernateLazyInitializer.GetImplementation() as T;
        }
        return list;
    }

Any suggestions?

dragonfly
  • 17,407
  • 30
  • 110
  • 219