Indeed, that class was registered as an entity and had a mapping defined. I had to split it up into two derivees. One for the component and one for the join.
Fortunately, that was easily possible in this case. BillingInfo BillingInfoForComponent:BillingInfo BillingInfoForJoin:BillingInfo (not actual names, just exemplifying) Then the mapping for join would use the forjoin class. I suppose it got confused by the entity mapping even though the parent entity being queried did not use a many-to-one to that child class in its mapping, but redefined it. Somewhat of an awkward problem to debug, and even if it's not a good practice, I'm still not sure why nhibernate goes after *other* registered mappings for the child class instead of honoring what the parent class defines. Thanks though! Everything seems to work now. P.S.: Would be great if the linq extension points were better documented! :) On May 5, 5:24 pm, Fabio Maulo <[email protected]> wrote: > because that class is registered as entity? > > -- > Fabio Maulo > > El 05/05/2011, a las 10:59, lege <[email protected]> escribió: > > > > > > > > > Ok, it appears I was wrong and nhibernate linq also suffers from the > > same problem with components, which I think is definitely a bug. > > > I was able to integrate my custom sql dialect function calls into > > nhibernate linq using some generator classes derived from > > BaseHqlGeneratorForMethod. > > (https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/ > > nhibernate/src/NHibernate.Test/Linq/CustomExtensionsExample.cs) > > > Everything works fine for the class that has the property mapped via > > many-to-one but the one the one with component it fails when executing > > the query with the following error: > > > Invalid join: p.BillingInfo > > [.Select(.Where(.Where(.Where(NHibernate.Linq.NhQueryable`1[.... > > > at > > NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.CreateFromJoinElement(IASTNode > > path, IASTNode alias, Int32 joinType, IASTNode fetchNode, IASTNode > > propertyFetch, IASTNode with) in d:\CSharp\NH\nhibernate\src\NHibernate > > \Hql\Ast\ANTLR\HqlSqlWalker.cs: line 694 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.joinElement() in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 3955 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.fromElement() in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 3617 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.fromElementList() in d:\CSharp > > \NH\nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 3391 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.fromClause() in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 3308 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.unionedQuery() in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 1645 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.query() in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 1510 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.selectStatement() in d:\CSharp > > \NH\nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 536 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.statement() in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\Generated\HqlSqlWalker.cs: > > line 435 > > at NHibernate.Hql.Ast.ANTLR.HqlSqlTranslator.Translate() in d:\CSharp > > \NH\nhibernate\src\NHibernate\Hql\Ast\ANTLR\QueryTranslatorImpl.cs: > > line 589 > > at > > NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2 > > replacements, Boolean shallow, String collectionRole) in d:\CSharp\NH > > \nhibernate\src\NHibernate\Hql\Ast\ANTLR\QueryTranslatorImpl.cs: line > > 396 > > at > > NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(I > > ASTNode > > ast, String queryIdentifier, String collectionRole, Boolean shallow, > > IDictionary`2 filters, ISessionFactoryImplementor factory) in d:\CSharp > > \NH\nhibernate\src\NHibernate\Hql\Ast\ANTLR > > \ASTQueryTranslatorFactory.cs: line 44 > > at > > NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(S > > tring > > queryIdentifier, IQueryExpression queryExpression, String > > collectionRole, Boolean shallow, IDictionary`2 filters, > > ISessionFactoryImplementor factory) in d:\CSharp\NH\nhibernate\src > > \NHibernate\Hql\Ast\ANTLR\ASTQueryTranslatorFactory.cs: line 27 > > at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String > > expressionStr, IQueryExpression queryExpression, String > > collectionRole, Boolean shallow, IDictionary`2 enabledFilters, > > ISessionFactoryImplementor factory) in d:\CSharp\NH\nhibernate\src > > \NHibernate\Engine\Query\HQLExpressionQueryPlan.cs: line 23 > > at > > NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression > > queryExpression, Boolean shallow, IDictionary`2 enabledFilters) in d: > > \CSharp\NH\nhibernate\src\NHibernate\Engine\Query\QueryPlanCache.cs: > > line 89 > > at > > NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression > > queryExpression, Boolean shallow) in d:\CSharp\NH\nhibernate\src > > \NHibernate\Impl\AbstractSessionImpl.cs: line 302 > > at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression > > queryExpression) in d:\CSharp\NH\nhibernate\src\NHibernate\Impl > > \AbstractSessionImpl.cs: line 258 > > at NHibernate.Linq.NhQueryProvider.PrepareQuery(Expression expression, > > ref IQuery query, ref NhLinqExpression nhQuery) in d:\CSharp\NH > > \nhibernate\src\NHibernate\Linq\NhQueryProvider.cs: line 42 > > at NHibernate.Linq.NhQueryProvider.Execute(Expression expression) in d: > > \CSharp\NH\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs: line 101 > > at Remotion.Data.Linq.QueryableBase`1.GetEnumerator() > > > Where p.BillingInfo is the component here. It's unclear to me why it > > tries to join on the component, any ideas? > > > On May 5, 2:07 am, lege <[email protected]> wrote: > >> The id of the entity is not being used explicitly anywhere. The > >> cascading mode takes care of any updates to this property, and > >> otherwise everything works fine. > > >> Nhibernate linq and hql can adapt the sql being executed easily on the > >> fly, it's just QueryOver and Criteria that are not. > > >> On May 5, 1:55 am, Fabio Maulo <[email protected]> wrote: > > >>> "The problem we're facing is that one of the classes uses a > >>> *<component> *mapping > >>> for a property, while another derivee uses a *many-to-one* for the same > >>> property." > > >>> The DB can be old but I would know why/when you need an Entity with its ID > >>> as a component. > >>> I have used a similar trick but with a read-only view and was a very ugly > >>> quick solution done 4 years ago. > >>> Believe me that is not a good idea especially if you are doing it with a > >>> read-write entity and/or with the cache enabled... compared the QueryOver > >>> "problem" is nothing. > > >>> On Wed, May 4, 2011 at 7:42 PM, lege <[email protected]> wrote: > >>>> Yes Fabio, same property of the same type. It's a legacy database > >>>> schema and it's pretty much impossible to change right now. > > >>>> On May 4, 11:12 pm, Fabio Maulo <[email protected]> wrote: > >>>>> "The problem we're facing is that one of the classes uses a > >>>>> *<component> *mapping > >>>>> for a property, while another derivee uses a *many-to-one* for the same > >>>>> property." > > >>>>> Same property of the same Type ? > > >>>>> On Wed, May 4, 2011 at 4:57 PM, Andrei Alecu <[email protected] > >>>>> wrote: > > >>>>>> Hello all, > > >>>>>> We heavily use inheritance in our data layer, almost every class we > >>>> have is > >>>>>> inherited from a base class and there are several derivees. > > >>>>>> Recently we tried to move a pretty big dynamic HQL query that was > >>>> getting > >>>>>> out of hand and was resulting in a lot of code duplication. > > >>>>>> The problem we're facing is that one of the classes uses a *<component> > >>>> *mapping > >>>>>> for a property, while another derivee uses a *many-to-one* for the same > >>>>>> property. > > >>>>>> Because of QueryOver needing explicit joins to be defined, I can't seem > >>>> to > >>>>>> easily create just one query that applies to both classes. Trying to > >>>> define > >>>>>> a JoinAlias() for the <component> relationship results in an error, and > >>>>>> queries for the derivee with many-to-one don't work without a > >>>> JoinAlias(). > >>>>>> It seems awkward to need to adapt my data access code based on the way > >>>> the > >>>>>> property is defined in the mapping, and seems like a leaky abstraction > >>>> API > >>>>>> design issue. > > >>>>>> I was able to work around this with some very ugly helper methods that > >>>>>> return various *System.Linq.Expressions.Expression<Func<* return types > >>>>>> based on which class is being worked on. > > >>>>>> Here's some code: > > >>>>>> Derivee1Repository.cs: > > >>>>>> protected virtual > >>>> System.Linq.Expressions.Expression<Func<TDerivee, object>> > >>>> CategoryNameExpression() > >>>>>> { > >>>>>> return p => CategoryAlias.CategoryName; // for the > >>>> many-to-one > >>>>>> } > > >>>>>> Derivee2Repository.cs: > > >>>>>> protected virtual > >>>> System.Linq.Expressions.Expression<Func<TDerivee, object>> > >>>> CategoryNameExpression() > >>>>>> { > >>>>>> return p => p.Category.CategoryName; // for the component, > >>>> can't use CategoryAlias here, it will throw an exception that Derivee > >>>> does > >>>> not contain a property called CategoryName > >>>>>> } > > >>>>>> Then the joint DeriveeRepositoryBase.cs could do, for example: > > >>>>>> query.Select(CategoryNameExpression()) > > >>>>>> Also, another problem seems to be that casts on aliases do not seem to > >>>> work > >>>>>> at all: > > >>>>>> Derivee1Repository.cs: > > >>>>>> query.JoinAlias(p => p.BillingInfo, () => BillingInfoAlias); // > >>>> separate table > > >>>>>> query.JoinAlias(() => BillingInfoAlias.PaymentMethod, () => > >>>> PaymentMethodAlias); > > >>>>>> Derivee2Repository.cs: > > >>>>>> query.JoinAlias(() => p.BillingInfo.PaymentMethod, () => > >>>> PaymentMethodAlias); // here billinginfo is just a component of the same > >>>> table: > > >>>>>> DeriveeRepositoryBase.cs: > > >>>> query.Select(()=>((CreditCard)PaymentMethodAlias).ExpirationDate); > >>>>>> // exception, Derivee does not contain property called ExpirationDate > >>>>>> query.Select(()=>PaymentMethodAlias.Id); // Id is defined on > >>>> base, > >>>>>> this works > > >>>>>> I wasn't able to use Projections.Property() either as a parameter for > >>>> the > >>>>>> method, unless someone can help with an idea on how to do the cast. > > >>>>>> It would be nice if there was a way for JoinAlias() to work with (or > >>>>>> silently ignore) components as well, allowing an alias to be defined > >>>> and > >>>>>> used the same as if it was a separate table. *OR*, even better would be > >>>> if > >>>>>> there was a way for QueryOver to allow Linq-like auto-joins of tables > >>>> if > >>>>>> they're needed. That would simplify our code tremendously.... > > read more » -- You received this message because you are subscribed to the Google Groups "nhusers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.
