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(IASTNode
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(String
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.
>
> > > > > Ideally, I'd use Nhibernate linq for this, which does not have any of
> > > these
> > > > > problems as far as I can tell but I need to call a custom function 
> > > > > that
> > > is
> > > > > specified in our custom Dialect, and I wasn't able to find how to call
> > > a
> > > > > custom function with nhibernate linq (if it's at all possible).
>
> > > > > So, to recap, the questions are:
> > > > > 1) Is the QueryOver behavior going to be fixed? Are there any plans on
> > > > > making it more like linq and not requiring explicit joins for
> > > everything?
> > > > > It's tedious and requires intimate knowledge of how mappings are
> > > defined,
> > > > > which breaks abstraction layers.
> > > > > 2) Any clues on the cast issue?
> > > > > 3) Is it possible to use nhibernate linq to call a custom function
> > > defined
> > > > > in the dialect? (it's a custom AddDays(prop1, prop2) function that we
> > > need,
> > > > > were both prop1 and prop2 are columns in the table)
>
> > > > > Thanks,
> > > > > Andrei
>
> > > > >  --
> > > > > 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.
>
> > > > --
> > > > Fabio Maulo
>
> > > --
> > > 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.
>
> > --
> > Fabio Maulo

-- 
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