Concat-ing two string props... should that property be mapped?

874 views
Skip to first unread message

kujotx

unread,
Jun 16, 2009, 1:56:48 PM6/16/09
to Fluent NHibernate
I have a derived class that uses a method from a value object. My
value object has first, last names, so I added a concatenation for
full name and other variations for Find() criteria.

The abbreviated version is shown below. My goal is to be able to do
something like the following p => p.Person.FullName.Contains("John
Doe");

I am using Nhibernate.Linq and Linq.Specifications. I was trying to
write a specification that included the

That fails. Is there a fluent nhibernate way that I can accomplish
this, or will the solution lie more in nhibernate?

Thanks,

Kurt

<code>
public class User : AbstractUser{
}

public abstract AbstractUser
{
public virtual Person Person {get; private set:}
}

public class Person{
public virtual string LastName {get; private set;}
public virtual string FirstName {get; private set;}

public Person (string firstName, string lastName){
FirstName = firstName;
LastName = lastName;
}

public string FullName{
get{
return string.Format("{0} {1}, FirstName, LastName");
}
}
}
</code>

Hudson Akridge

unread,
Jun 16, 2009, 3:12:16 PM6/16/09
to fluent-n...@googlegroups.com
Your question isn't specifically a fluent way that I'm aware of, you're just looking for a way to map a model formula property to the database, for querying, but that doesn't get read out of the database (because again, it's calculated in the model based on the other two properties). Is that correct?

In NHibernate, look at mapping the FullName property using a:
access="NHibernate.Properties.ReadOnlyAccessor, NHibernate"

Attribute. The ReadOnlyAccessor may be exactly what you want there.

I don't have the source of fluent available to me right now, but I don't believe we currently support the ReadOnlyAccessor, so you might be stuck setting that manually with SetAttribute for now (although expect that method to go away here soon in trunk), or you can just modify your version of FNH to support that.

Kurt Johnson

unread,
Jun 17, 2009, 9:55:57 AM6/17/09
to Fluent NHibernate
Thanks for the reply, Hudson.

I will take a look at the NHibernate docs and try and implement that.
It sounds like my virtual method needs to be mapped with a readonly
accessor (?) so that it doesn't go out to via nhib in outgoing DDL,
but can be interpreted by the HQL parser in selects. Am I on the right
track?

I was thinking that the conversion from Linq\POCO would occur first --
via an expression tree -- then, translated to HQL as the concatention
of the two fields.

So much to learn... and I love it.

Thanks again,
Kurt

Hudson Akridge

unread,
Jun 17, 2009, 9:59:44 AM6/17/09
to fluent-n...@googlegroups.com
It sounds like my virtual method needs to be mapped with a readonly
accessor (?) so that it doesn't go out to via nhib in outgoing DDL,
but can be interpreted by the HQL parser in selects. Am I on the right
track?

Yup, you're on the right track :) But it's the inbound nhib that you're looking to avoid (the rehydration part) Basically the ReadOnlyAccessor allows NHibernate to persist the value, but not retrieve it. However, that value is stored in the database, and thus, available for HQL queries, which is really just a DSL that sits on top of SQL.

Think of it like this. If it's not available in SQL to write a query by hand, then it's not available for HQL. ReadOnlyAccessor gives you the optimization of saying that this property will only ever be queried on, so persist it into the DB, but the DB is not used to evaluate the value in the domain model.

Kurt Johnson

unread,
Jun 17, 2009, 7:32:17 PM6/17/09
to Fluent NHibernate
I think I got it. I missed the entire concept of persisting the
property result as the end-game. I was expecting NHibernate.Linq to
translate some expression tree of my FullName property into a criteria
for me.

I finally understand the concept, yet I am bit bummed. Maybe there is
some futuristic alien race that has a library for my desired code-
witchery (or, I can get cracking on my own patch).

Disappointed but now back-on-board, I went ahead and mapped the above
property FullName (after adding an empty setter) accordingly with a
SetAttribute for "access" as "readonly".

Now, my updates to my FirstName and LastName are persisting to the
database the FullName column. Also, I am able to query that column in
the database.

Thanks again, Hudson. That was precisely what I needed!

Paul Batum

unread,
Jun 20, 2009, 8:31:19 AM6/20/09
to fluent-n...@googlegroups.com
Hi Kurt,

For future reference, generally you can tell if your code has a chance of being converted to an expression tree by examining the argument or return signature. So for your example:


  public string FullName{
               get{
                       return string.Format("{0} {1}, FirstName, LastName");
               }
       }

Currently, there is no way to get an expression tree of that code. The code you want converted to an expression tree has to be returned as an Expression<T>. So there is no hope for the above example being converted to SQL and being executed against the DB. A format that would have more of a chance would look something like this:

public Expression<Func<Customer, string>> GetFullNameExpression = c => string.Format("{0} {1}, c.FirstName, c.LastName");

public string FullName
{
  get { return GetFullNameExpression.Compile()(this); }
}

In the above example, the code for determining the full name is exposed as an Expression<T> (where T is Func<Customer, string>).  Now if you passed the GetFullNameExpression to a method that was expecting an expression, that method could potentially inspecting the expression and building a different representation, such as a SQL query.

In summary, expression tree acrobatics are only possible if you are returning or passing your code as an Expression<T>.

Paul Batum

John Rayner

unread,
Jun 23, 2009, 7:01:42 PM6/23/09
to Fluent NHibernate
From a purely NHib viewpoint, you don't need to persist the computed
value. You can map a formula like so and then you can use it in your
Linq specifications just like any other property:

<property name="FullName" formula="FirstName + ' ' + LastName" />

I don't know how this would (could?) get mapped in FNH <blush/>

The other option is to shift the computation into your database, but
that depends on your RDBMS. SQL Server is capable of supporting
computed columns on a table, so I would expect most others could too.

Note: both of these options could map into a straightforward property
on your class, but then you won't get the FullName property updating
in response to a change on the FirstName property. If you need that,
then you'll need to code it up within your class.

Cheers,
John
> > - Hudsonhttp://www.bestguesstheory.comhttp://twitter.com/HudsonAkridge- Hide quoted text -
>
> - Show quoted text -
Reply all
Reply to author
Forward
0 new messages