From: NHibernate J. <nh...@gm...> - 2008-06-13 12:59:12
|
QueryTranslator: Invalid Cast to object array when using IResultTransformer --------------------------------------------------------------------------- Key: NH-1344 URL: http://jira.nhibernate.org/browse/NH-1344 Project: NHibernate Issue Type: Patch Components: Core Affects Versions: 2.0.0.Alpha1, 1.2.1, 1.2.0.GA, 2.0.0.Alpha2, 2.0.0.GA Reporter: Stefan Simroth Priority: Minor Attachments: QueryTranslatorInvalidCastToObjectArray20trunk.patch there seems to be an issue with a hard cast in the QueryTranslator class, line 1452 (trunk) - resp. line 1288 (1.2.1) ... The hard cast in method GetResultList to an object[] fails in the case of my company's product, when using an IResultTransformer. I chose to use an IResultTransformer implementation for Criteria's and Query's to be able to set a required property. It seems an appropriate way to me and my tests (and the running app) ensure that it works. However, I had to patch the QueryTranslator at the locations mentioned above, because it threw an invalid cast exception (stacktrace below) - because the IList of my objects could not be casted to an object[]. Debugging it, showed me that the "results" list contained my domain objects, but it could not be casted to an object[]. It was a collection of my domain types and my domain types are no object[]. Now, some time passed by since then, and our product works fine with the patch, so unfortunately I forgot the exact reason, but I'd guess, I used the generic Query signature and so the results list was a generic list that cannot be casted to object[]. But also ArrayList or Hashtable cannot be casted to object[]... A little experiment, gave me the compiler error: Cannot convert type 'System.Collections.Generic.List<ConsoleApplication1.Project>' to 'object[]' class Program { static void Main(string[] args) { List<Project> projects = new List<Project>(); object[] objs = (object[]) projects; } class Project { } } => same thing doesn't work with ArrayList or Hashtable ... ---- The code snippet from QueryTranslator in question: for (int i = 0; i < results.Count; i++) { object[] row = (object[]) results[i]; results[i] = holderInstantiator.Instantiate(row); } ---- Patch - with a "safe" cast: object[] row = results[i] as object[]; if (row != null) { results[i] = holderInstantiator.Instantiate(row); } The included patch is for the NHibernate 2.0 trunk. The same problem exists in earlier versions, namely 1.2. I might be totally missing the root of the problem, but please excuse this, as I am not familiar with the NHibernate internals, but tried to apply a patch at the right place to enable the very useful feature of the IResultTransformer to our case - and maybe to others in future. Here is the stacktrace: (version 1.2.1) at NHibernate.Hql.Classic.QueryTranslator.GetResultList(IList results, IResultTransformer resultTransformer) in d:\dev\yap\nhibernate\trunk\src\NHibernate\Hql\Classic\QueryTranslator.cs:line 1291 at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) in d:\dev\yap\nhibernate\trunk\src\NHibernate\Loader\Loader.cs:line 1744 at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet querySpaces, IType[] resultTypes) in d:\dev\yap\nhibernate\trunk\src\NHibernate\Loader\Loader.cs:line 1738 at NHibernate.Hql.Classic.QueryTranslator.List(ISessionImplementor session, QueryParameters queryParameters) in d:\dev\yap\nhibernate\trunk\src\NHibernate\Hql\Classic\QueryTranslator.cs:line 1124 at NHibernate.Impl.SessionImpl.Find(String query, QueryParameters parameters, IList results) in d:\dev\yap\nhibernate\trunk\src\NHibernate\Impl\SessionImpl.cs:line 1763 ---- My IResultTransformer implementation: #region IResultTransformer Members public object TransformTuple(object[] tuple, string[] aliases) { object o = CriteriaUtil.RootEntity.TransformTuple(tuple, aliases); TrySetDomainModelStore(o); return o; } public IList TransformList(IList collection) { for (int i = 0; i < collection.Count; i++) { TrySetDomainModelStore(collection[i]); } return collection; } #endregion TranformTuple is called rarely. TransformList is called after the HolderInstantiator call. I never create a new MyEntity[] { my, domain, entities}, nor a new object[] { my, domain, entities} ... ------ Felix Gartsman: Isn't this similar to Hibernate issues: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2463 http://opensource.atlassian.com/projects/hibernate/browse/HHH-2525 They are also present in NH, and they prevent caching queries with IResultTransformer - the caching thinks it gets a tuple, but it's actually the transformed object. -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.nhibernate.org/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira |