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.
