Question

I would like to know if there is a way to create a Restriction on a primitive collection of a Model in NHibernate.3.3.3?

Here's the details:

class Parent { 
    IEnumerable<string> ChildNames { get; set; }

}

I need to search like so:

private DetachedCriteria BuildQuery() {
    var inNames = { "Bob", "Sam", "Dan" };
    var query = DetachedCriteria.For<Parent>("parent");
    query.Add(Restrictions.In("ChildNames", inNames));
    return query;
}

I found this old question that says it's not possible, but given the fact that it's old and doesn't have a ton of upvotes, I'd like to confirm before I refactor.

If I can do it and I'm totally botching it, I'll take that help as well!

Was it helpful?

Solution 2

I ended up, like many, refactoring the collection into a strong type.

OTHER TIPS

In this scenario, we can use Projection (something less type-safe, then mapped Property, but more flexible).

Let's expect the mapping like this:

<bag name="ChildNames" inverse="false" lazy="true" table="[dbo].[ChildNames]" 
    cascade="all"
    batch-size="25">
  <key column="ParentId" />
  <element type="System.String" column="ChildName" />
</bag>

Then we can adjust the Build query method like this:

protected virtual DetachedCriteria BuildQuery()
{
    var inNames = new [] { "Bob", "Sam", "Dan" };

    // parent query reference
    var query = DetachedCriteria.For<Parent>("parent");
    // reference to child query
    var child = query.CreateCriteria("ChildNames");

    // let's project the column name of the Element, e.g. 'Name'
    var columnNameProjection = Projections.SqlProjection(
        "ChildName as name", null, new IType[] { NHibernateUtil.String }
        );

    // in clause
    child.Add(Restrictions.In(
        columnNameProjection, inNames
        ));

    return query;
}

And this is what we will get:

SELECT ...
 FROM Parent this_ 
  inner join [dbo].[ChildNames] childNames3_ 
    on this_.ParentId=childNames3_.ParentId 
 WHERE ChildName in (@p0, @p1, @p2)
 ...
 @p0=N'Bob',@p1=N'Sam',@p2=N'Dan'

The caveat:

While this is in deed working... the ChildName is used without the Alias. That could be pretty tricky to fulfill... so be careful, if there are more columns with the name ChildName in this scenario

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top