Linq to NHibernate: how to query on a property without setter

Print Content | More

Recently I’ve started to play with Linq to NHibernate and I have to say it work pretty well for the scenarios I’m facing. It also helped me to ‘re-learn’ some things on NHibernate I usually forget.

Let’s consider the case in which we have a class that have some properties without setters, the usual way to map them is using the access=’field’ modifier and tell NHibernate to not use the property by the internal field of the implementation; you can then write your HQL queries on that field, here’s an example:

Public Class IDGEN
 
    Private mID As Int64 = -1
    Public Overridable ReadOnly Property ID() As Int64
        Get
            Return mID
        End Get
    End Property
 
    Private mYear As Int16
    Public Overridable ReadOnly Property Year() As Int16
        Get
            Return mYear
        End Get
    End Property
 
End Class

Here is the mapping I was used to have:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Entities.IDGEN, CommunicationModule" table="tblPROTOCOL_ID_GENERATOR" lazy="false" >
    <id name="mID" column="ID" type="Int64" access="field" unsaved-value="-1">
      <generator class="native" />
    </id>
    <property name="mYear" column="Year" type="Int16" access="field" insert="false" update="false" />
  </class>
</hibernate-mapping>

You see we refer to the internal implementation members and our HQL queries will look like:

select max(id.mID) from IDGEN id where id.mYear = :year

As an experiment I’m porting this code to use Linq to NHibernate, the link query I would like to write is this:

long idgen = Session.Linq<Idgen>().Where(i => i.Year == year).Max(i => i.ID);

You can easily see the problem here: in code I cannot refer to the private mYear or mID fields, so when the query translator tries to parse my expression I get a wonderful exception.

How to make this work ? The answer is simple and built into NHibernate we can use Access and Naming strategies, look at 'Chapter 5.1.9 property' of the NHibernate reference documentation.

There you can see how to tell NHibernate to use the Getter of the properties to retrieve values from the class, and how the internal field is called so it can use that when assigning values to object.

In the end it’s just a matter of writing the right mappings, with something like this:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="SID.Gestione.RefertiDocumenti.Neurologia.Entities.Idgen, SID.Gestione.RefertiDocumenti.Neurologia" table="IncrementalNumberGenerator" lazy="false" >
    <id name="ID" column="ID" type="Int64" access="nosetter.pascalcase-m" unsaved-value="-1">
      <generator class="native" />
    </id>
    <property name="Year" column="Year" access="nosetter.pascalcase-m" type="Int16" insert="false" update="false" />
  </class>
</hibernate-mapping>

we are now able to make the former Linq query work.

We now refer to the actual property of the class, we specify we don’t have setter and we use the pascalcase-m notation for the internal fields.

So fixing all your previous mapping that used access=’field’ attribute to a more correct notation you can easily perform Linq queries on all your classes.



Access, Field, Linq, Nhibernate, Nosetter, Setter

0 comments

Related Post

All fields are required and you must provide valid data in order to be able to comment on this post.


(will not be published)
(es: http://www.mysite.com)