<Any/> Query with Linq

40 views
Skip to first unread message

MichaelK

unread,
Sep 9, 2010, 4:45:04 PM9/9/10
to nhusers
Is it possible to query an <Any/> collection by the type. Take the
pretend Any mapping below. Can I find all Circles in the ToyBox using
linq?

<class name=ToyBox >
<any name="Items" meta-type="int" id-type="int">
<meta-value class="1" value="Square"/>
<meta-value class="2" value="Circle"/>
<column name="entityTypeId"/>
<column name="entityId"/>
</any>
</class>

Here is how I would have hoped to query it.

Session.Query<ToyBox>().Where(x => x.Items.GetType() ==
typeof(Circle))

José F. Romaniello

unread,
Sep 9, 2010, 4:51:22 PM9/9/10
to nhu...@googlegroups.com
what about this one?

Session.Query<ToyBox>().Where(x => x.Items is Circle)

or

Session.Query<ToyBox>().Where(x => x.Items.OfType<Circle>().Any());


2010/9/9 MichaelK <mko...@gmail.com>

Fabio Maulo

unread,
Sep 9, 2010, 7:19:23 PM9/9/10
to nhu...@googlegroups.com
I like the classes named "1" and "2"

--
Fabio Maulo

> --
> You received this message because you are subscribed to the Google Groups "nhusers" group.
> To post to this group, send email to nhu...@googlegroups.com.
> To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.
>

MichaelK

unread,
Sep 10, 2010, 12:01:28 PM9/10/10
to nhusers
The above queries do not work. Here is a working example with mapping
and classes

Cirlce, Square, Triangle all implement IShape. ToyBox entity has a
property called Shape.

public class Circle : IShape
{
public virtual int Id { get; set; }
public virtual string Color { get; set; }
}

public class Square : IShape
{
public virtual int Id { get; set; }
public virtual string Color { get; set; }
}

public class Triangle : IShape
{
public virtual int Id { get; set; }
public virtual string Color { get; set; }
}

public class ToyBox
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IShape Shape { get; set; }
}

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Test"
namespace="Test">

<class name="Circle" table="circles">
<id column="circle_id" name="Id" type="int">
<generator class="identity"/>
</id>
<property name="Color" column="color" />
</class>

<class name="Square" table="squares">
<id column="square_id" name="Id" type="int">
<generator class="identity"/>
</id>
<property name="Color" column="color" />
</class>

<class name="Triangle" table="triangles">
<id column="triangle_id" name="Id" type="int">
<generator class="identity"/>
</id>
<property name="Color" column="color" />
</class>

<class name="ToyBox" table="toyBox">
<id column="toybox_id" name="Id" type="int">
<generator class="identity"/>
</id>
<property name="Name" column="name" />
<any name="Shape" id-type="int" meta-type="int">
<meta-value value="1" class="Circle"/>
<meta-value value="2" class="Square"/>
<meta-value value="3" class="Triangle"/>
<column name="s_object_id" not-null="true"/>
<column name="object_id" not-null="true"/>
</any>
</class>
</hibernate-mapping>

I can get a ToyBox by ID and when I look at the Shape Property its
hydrated properly.

BUT I can not query on Shape. The below query fails

var entity = Session.Query<ToyBox>().Where(x => x.Shape is
Circle).FirstOrDefault();

Error:
System.NullReferenceException: Object reference not set to an instance
of an object.
at
NHibernate.Hql.Ast.ANTLR.SessionFactoryHelperExtensions.FindSQLFunction(String
functionName)
at NHibernate.Hql.Ast.ANTLR.Tree.IdentNode.get_DataType()
at
NHibernate.Hql.Ast.ANTLR.Tree.BinaryLogicOperatorNode.ExtractDataType(IASTNode
operand)
at NHibernate.Hql.Ast.ANTLR.Tree.BinaryLogicOperatorNode.Initialize()
at
NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.PrepareLogicOperator(IASTNode
operatorNode)
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.comparisonExpr()
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.logicalExpr()
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.whereClause()
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.unionedQuery()
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.query()
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.selectStatement()
at NHibernate.Hql.Ast.ANTLR.HqlSqlWalker.statement()
at NHibernate.Hql.Ast.ANTLR.HqlSqlTranslator.Translate()
at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Analyze(String
collectionRole)
at
NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2
replacements, Boolean shallow, String collectionRole)
at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Compile(IDictionary`2
replacements, Boolean shallow)
at
NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode
ast, String queryIdentifier, String collectionRole, Boolean shallow,
IDictionary`2 filters, ISessionFactoryImplementor factory)
at
NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String
queryIdentifier, IQueryExpression queryExpression, String
collectionRole, Boolean shallow, IDictionary`2 filters,
ISessionFactoryImplementor factory)
at
NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String
expressionStr, IQueryExpression queryExpression, String
collectionRole, Boolean shallow, IDictionary`2 enabledFilters,
ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String
expressionStr, IQueryExpression queryExpression, String
collectionRole, Boolean shallow, IDictionary`2 enabledFilters,
ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String
expressionStr, IQueryExpression queryExpression, Boolean shallow,
IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at
NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression
queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at
NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression
queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression
queryExpression)
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression)
at NHibernate.Linq.NhQueryProvider.Execute[TResult](Expression
expression)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
DogRepositoryTests.cs(32,0): at
NHibernateScratchpad.Tests.ToyBoxRepositoryTests.Test()

On Sep 9, 7:19 pm, Fabio Maulo <fabioma...@gmail.com> wrote:
> I like the classes named "1" and "2"
>
> --
> Fabio Maulo
>

MichaelK

unread,
Sep 10, 2010, 12:18:25 PM9/10/10
to nhusers
Little more info to help figure out what is going on. When I use
QueryOver<>.Where(x => x.Shape is Cirlce) I get this error

Execute
System.Exception: Could not determine member type from (x.Shape Is
Circle)
at
NHibernate.Impl.ExpressionProcessor.ProcessBooleanExpression(Expression
expression)
at NHibernate.Impl.ExpressionProcessor.ProcessExpression(Expression
expression)
at
NHibernate.Impl.ExpressionProcessor.ProcessLambdaExpression(LambdaExpression
expression)
at NHibernate.Impl.ExpressionProcessor.ProcessExpression[T]
(Expression`1 expression)
at NHibernate.Criterion.QueryOver`2.Add(Expression`1 expression)
at NHibernate.Criterion.QueryOver`2.Where(Expression`1 expression)
at
NHibernate.Criterion.QueryOver`2.NHibernate.IQueryOver<TRoot,TSubType>.Where(Expression`1
expression)
DogRepositoryTests.cs(32,0): at
NHibernateScratchpad.Tests.ToyBoxRepositoryTests.Test()

MichaelK

unread,
Sep 10, 2010, 12:24:41 PM9/10/10
to nhusers
Sorry for the mass updates but I keep getting closer. I got it working
with QueryOver, but Linq fails. I have two UnitTests below. One using
QueryOver<> that WORKS, and second using Linq that fails. Is this a
bug with the Linq provider?? Also note how I had to create a circle
as well for the query to work. I still would like to get all ToyBoxes
with Shape of type Circle.

[Test]
public void Test()
{
var entity = Repository.Session.QueryOver<ToyBox>()
.Where(x => x.Shape == new Circle { Id =
1 }).SingleOrDefault();
Assert.IsNotNull(entity);
}

[Test]
public void Test1()
{
var entity = Repository.Session.Query<ToyBox>()
.Where(x => x.Shape == new Circle { Id =
1 }).SingleOrDefault();
Assert.IsNotNull(entity);

José F. Romaniello

unread,
Sep 10, 2010, 12:58:17 PM9/10/10
to nhu...@googlegroups.com
1-Yes it is a bug in the linq provider. You can submit a test case to the issue tracker http://jira.nhforge.org/
2-I dont like your QueryOver query Where(x => x.Shape == new Circle { Id = 1 })) ... Its feel just wrong. 
3-In the first mail you said, "Can I find all Circles in the ToyBox using linq?" So I wonder if the query you are looking for is something like this:

session.Query<ToyBox>().Where(tb => tb.Id = someId...).Select(tb => tb.Shape.OfType<Circle>()).First()...

Or something like that?
I don't know if this work, it could fail too... But i think this is the query you need.

2010/9/10 MichaelK <mko...@gmail.com>

MichaelK

unread,
Sep 10, 2010, 1:18:53 PM9/10/10
to nhusers
In #3, your query will not work since its not an IEnumerable. Shape is
just a single object. I tried below test and I get different Error.
Looks like its not looking at Any mapping to get the meta-value value.
In this case Circle = 1.

[Test]
public void Test44()
{
var entity = Repository.Session.QueryOver<ToyBox>()
.Where(x => x.Shape.GetType() ==
typeof(Circle)).List();
Assert.IsNotNull(entity);
}

Execute
NHibernate.Exceptions.GenericADOException: could not execute query
[ SELECT this_.toybox_id as toybox1_5_0_, this_.name as name5_0_,
this_.s_object_id as s3_5_0_, this_.object_id as object4_5_0_ FROM
toyBox this_ WHERE this_.s_object_id = ? ]
Positional parameters: #0>Touchcom.Objects.Entities.Circle
[SQL: SELECT this_.toybox_id as toybox1_5_0_, this_.name as name5_0_,
this_.s_object_id as s3_5_0_, this_.object_id as object4_5_0_ FROM
toyBox this_ WHERE this_.s_object_id = ?] --->
System.InvalidCastException: Unable to cast object of type
'System.RuntimeType' to type 'System.String'.


On Sep 10, 12:58 pm, José F. Romaniello <jfromanie...@gmail.com>
wrote:
> 1-Yes it is a bug in the linq provider. You can submit a test case to the
> issue trackerhttp://jira.nhforge.org/
> 2-I dont like your QueryOver query Where(x => x.Shape == new Circle { Id = 1})) ... Its feel just wrong.
>
> 3-In the first mail you said, "Can I find all Circles in the ToyBox
> using linq?" So I wonder if the query you are looking for is something like
> this:
>
> session.Query<ToyBox>().Where(tb => tb.Id = someId...).Select(tb =>
> tb.Shape.OfType<Circle>()).First()...
>
> Or something like that?
> I don't know if this work, it could fail too... But i think this is the
> query you need.
>
> 2010/9/10 MichaelK <mkob...@gmail.com>
> ...
>
> read more »

José F. Romaniello

unread,
Sep 10, 2010, 2:07:29 PM9/10/10
to nhu...@googlegroups.com
oh i see now. I thought it was a collection, but you are right, it is just an any.. So sorry.
It is a bug, would you mind to create an issue on jira?

btw, I am pretty sure you can query this in hql, 

from ToyBox t where t.Shape.class = 'full type name'

for instance;

session.CreateQuery("from ToyBox t where t.Shape.class = :shapeClass")
   .SetParameter("shapeClass", typeof(Circle).FullName)
   .List<ToyBox>();

(i prefer named queries, though)



2010/9/10 MichaelK <mko...@gmail.com>

MichaelK

unread,
Sep 10, 2010, 2:59:49 PM9/10/10
to nhusers
Yes I will add a bug. Thanks for the help.

On Sep 10, 2:07 pm, José F. Romaniello <jfromanie...@gmail.com> wrote:
> oh i see now. I thought it was a collection, but you are right, it is just
> an any.. So sorry.
> It is a bug, would you mind to create an issue on jira?
>
> btw, I am pretty sure you can query this in hql,
>
> from ToyBox t where t.Shape.class = 'full type name'
>
> for instance;
>
> session.CreateQuery("from ToyBox t where t.Shape.class = :shapeClass")
>    .SetParameter("shapeClass", typeof(Circle).FullName)
>    .List<ToyBox>();
>
> (i prefer named queries, though)
>
> 2010/9/10 MichaelK <mkob...@gmail.com>
> ...
>
> read more »

Mohamed Meligy

unread,
Sep 10, 2010, 5:43:14 PM9/10/10
to nhu...@googlegroups.com
And I like your comment about the "example" class name that "just aims at showing 2 different classes", Fabio.

And highly appreciate Jose's answer on the message topic that got me wondering the same also. Thanks.

Richard Brown (gmail)

unread,
Sep 11, 2010, 8:32:19 AM9/11/10
to nhu...@googlegroups.com
Hi Michael,
 
I think the syntax you'd want for QueryOver is:
 
var entity =
    Repository.Session
        .QueryOver<ToyBox>()
            .Where(tb => tb.GetType() == typeof(Circle))
            .SingleOrDefault();
 
2-I dont like your QueryOver query Where(x => x.Shape == new Circle { Id = 1 })) ... Its feel just wrong. 
 
           var entity = Repository.Session.QueryOver<ToyBox>()

Richard Brown (gmail)

unread,
Sep 11, 2010, 9:09:44 AM9/11/10
to nhu...@googlegroups.com
The 'is' operator syntax is nicer too, so in the trunk you can now write:
 
var entity = Repository.Session
    .QueryOver<ToyBox>()
        .Where(tb => tb is Circle)
        ...
 
(note - this change was only for QueryOver)
Reply all
Reply to author
Forward
0 new messages