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.

Reply via email to