NHibernate force not-found ignore to not execute a

2019-01-26 20:03发布

问题:

I'm working with a legacy database where FK's aren't always used. For example I have an entity Person and an entity Country. A person has a Country which is mapped as a many-to-one in the Person mapping.

<many-to-one name="Country" class="Country" foreign-key="none" lazy="false" not-found="ignore" fetch="join" outer-join="true" column="countryid"/>

When person has null as column value (countryid) it won't perform an extra select query (because it knows that there won't be a reference in the country table), but when a person has 0 as column value NH will perform another select to check the country tabel wether the country actually doesn't exist. But because we do a left outer join, NH should already know that it doesn't exist. Just to clarify, if a the column has a value of 1 and it is present in the country table, it will not perform an extra select.

Is there anyway to tell NHibernate not to do the extra select query?

Thanks

回答1:

No, there is no way how to do this via configuration. Nice post how to improve the not-found="ignore" functionality:

http://nhforge.org/blogs/nhibernate/archive/2011/01/28/how-to-use-0-instead-of-null-for-foreign-keys.aspx

We can use some of NHibernate extension points like custom PocoEntityTuplizer, but there is no simple configuration, no setting...

Some extract: from the link above (read it to get more details). During the build process of the Person entity will collection object[] values contain also CountryProxy. Let's say that missing in DB is one with Id == 0 (use your own logic there as needed). This proxy will be replaced with null so no SELECT will be executed...

public class NullableTuplizer : PocoEntityTuplizer
{
    public override void SetPropertyValues(object entity, object[] values)
    {
        for (int i = 0; i < values.Length; i++)
        {
            if (typeof (Country).IsAssignableFrom(getters[i ].ReturnType)
                && ((Country) values[i]).Id == 0) // missing id 
            {
                values[i] = null; // here change a Proxy to null
            }
        }
        base.SetPropertyValues(entity, values);
    }
...