Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I query a UserType with several properties mapped to a single column?

I have the following domain model:

public class Name
{
    private readonly string fullName;
    public Name(string fullName) { this.fullName = fullName }
    public string FullName { get { return fullName; } }
    public string FirstName { get { /* ... */ } }
    public string MiddleNames { get { /* ... */ } }
    public string LastName { get { /* ... */ } }
    public static implicit operator Name(string name) { /* ... */ }
}

public class Person
{
    public Name BirthName { get; set; }
    public Name Pseudonym { get; set; }
}

I implemented IUserType so I can map each name to a single database column with the full name.

Queries like this work:

var people = session.QueryOver<Person>()
                    .Where(p => p.Name == "John Doe")
                    .List();

But I can't query like this:

var people = session.QueryOver<Person>()
                    .Where(p => p.Name.LastName == "Doe")
                    .List();

Can I make NHibernate work with this?

like image 201
R. Martinho Fernandes Avatar asked May 01 '11 01:05

R. Martinho Fernandes


2 Answers

I'm not much of a nhibernate user, but analyzing all the information we have here about the scenario, I have a strong feeling that the answer is you can't.

You are mapping the value contained in that class to a single value in the db.

For it to allow querying on its pieces, it'd have to understand how all those sub pieces of information in the Name class are related to the full value.

That'd mean understanding what the custom c# code you have there is doing.


update 1:

Above answer is regarding having it all automatically generated for you And using the exact query you mentioned there.

You can definitely work around the problem like suggested by @cs. That is, defining an user defined function that does what you want, and mapping that in nHibernate.

At the very least that'd allow you do do something like:

session.QueryOver<Person>()
        .Where(p => session.PersonLastName(p) == "Doe")
        .List();

Another way would be to define an extension method that is translated to what you want, implementing it like in this article: http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html

Usage then would be like:

 session.QueryOver<Person>()
     .Where(p=> p.Name.LastNameExt() == "Doe")// Ext just to avoid name collision
     .List();

Finally, I'm not sure if it's possible to map the sub properties to user defined functions for each, so that your query can remain unchanged like:

 session.QueryOver<Person>()
                .Where(p => p.Name.LastName == "Doe")
                .List();

Not that in all cases you are changing from concatenating data to parsing data. You are the only one to know if that is really buying you anything, vs. keeping the properties separately.

like image 59
eglasius Avatar answered Sep 20 '22 14:09

eglasius


I believe it's possible, but will require some work on the SQL side of things. The first thing I would probably try is to create a UDF of some sort that will split up the name for you and do the necessary comparison. You can then extend NHibernate to map to this UDF and you should be able to invoke this function from your query, whether it's SQL, HQL, or ICriteria based.

like image 43
csano Avatar answered Sep 19 '22 14:09

csano