0
votes

I have an existing class that I'd like to persist as-is.

class Foo
{
    public int Id;
    ...
}

I have the following ClassMap:

class FooMap : ClassMap<Foo>
{
    Id(x => x.Id);
    ...
}

Building a session factory results in an invalid cast exception. My setup works if my entity class has the standard "public virtual int Id { get; private set; }" property. I'm interested in learning if I can use the field "public int Id" as the nhibernate Id.

Edit

It looks like you can't currently do this with FluentNHibernate, because it always excepts to deal with properties. This can be accomplished by mixing in an NHibernate xml mapping. Details on the mailing list.

2

2 Answers

1
votes

I've also answered this question on the mailing list (it was cross posted there) but I thought it would be useful to clarify here too.

Unfortunately Fluent NHibernate currently assumes that you are passing it a lambda expression that refers to a property (this assumption is manifested by a heavy reliance on the PropertyInfo type) . As a result of this, this line will fail at runtime if Id is a field rather than a property:

Id( x => x.Id).Access.Field();

We intend to resolve this issue eventually by removing our dependence on PropertyInfo.

2
votes

If you specify that lazy loading at the class level should not be used (that is, NHibernate should not create proxies for your objects), then you do not have to make all your properties virtual.

By default, NHibernate creates a proxy when it retrieves an instance of your entity from the DB. That is, it returns an 'empty' object for which only the Id field has been populated. Only when you need any other property of that object, the object itself is retrieved.

If you do not want this behaviour, you can turn it off by specifying 'lazy = false' at the class level. With a hbm - mapping file, you do it like this:

<class name="MyClass" table="sometable" lazy="false">
</class>

But, I do not know how to do it in Fluent; I haven't played with fluent yet.

edit: By all means, NHibernate has to have a way to set the field. In order to do this, you have 2 options:

  • first option is the solution you've already given by providing a private setter
  • second option is not to use automatic properties, and create your property like this:

    public class MyClass
    {
    
        private int _id;
    
        public int Id { get { return _id; } }
    }
    

    Then, in your mapping you have to define that NHibernate should use the backing field instead of the property when setting its value. Iin a hbm mapping file, you do it like this:

    <property name="Id" column="columnname" access="field.camelcase-underscore" />
    

    As you can see, you specify that NHibernate should use the field, and that it can find the field by applying the given naming strategy. (In this case, the field has the same name as the property, but it is prefixed with an underscore, and is written in camelcase (first character being lowercase). (For an identity, it should work as well:

    <id name="Id" column="..." access="field.camelcase-underscore" />
        <generator ... />
    </id>
    

In order to map fields instead of properties, you just have to define

access="field"

in the mapping file. But again, I do not know how to do it using Fluent ... Guess I urgently have to take a look at Fluent.

edit: Ok, I've downloaded Fluent. :) Isn't it possible to do it like this:

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Id( x => x.Id).Access.Field ();
    }
}

?