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?

有帮助吗?

解决方案

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.

其他提示

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.

You'll only be able to query against the full name, due to it's being just one database field.

If you map it differently so that FirstName and Lastname are separate columns you should be able to query on each of them, but you might then have difficulty querying on a property called FullName.

You need to create computed columns. They will be read-only but you can query against them. See here.

What you could do is implement your own repository wrapper for these objects and implement methods such as GetUsersByLastName() that could use HQL to perform these types of "search by partial value" queries.

Something like the following should allow you to search by any partial value provided you pass in the right search string:

var hql = "select p from People p where lower(p.BirthName) like :searchText";

Edit:

Removed LastName from query. The way this would work is you would utilize the anchored search text to either the beginning or ending of the BirthName field. For example if you wanted to search for all people with last name's of Smith you could do:

var hql = "select p from People p where lower(p.BirthName) like '% smith'";

And in the case of people with first name Joe:

var hql = "select p from People p where lower(p.BirthName) like 'joe %'";
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top