NHibernate, сохранить нулевое значение ссылки в БД как 0 (ноль) - PullRequest
1 голос
/ 13 марта 2012

Я нашел этот пример tuplizer для сохранения 0 при сохранении нулевых отношений.Это необходимо, так как я работаю над приложением на устаревшей схеме базы данных.

Я попробовал tuplizer здесь: http://nhforge.org/blogs/nhibernate/archive/2011/01/28/how-to-use-0-instead-of-null-for-foreign-keys.aspx

В этом примере я получил исключение nullreference дляПроксиФабрика.Затем я нашел обновление кода здесь: https://bitbucket.org/jfromaniello/hotgazpachoeg/changeset/87ac41c473ae

Однако, это также не работает для меня.В последнем методе, SetPropertyValues ​​(описывается как грязный хак 3, используемый при чтении объекта из БД), я получаю исключение nullref для этой части, если (typeof (IEntity), при чтении не связанного объекта (не Sample)

Мое сопоставление выглядит следующим образом (упрощенно):

   Table("ej_sample");
        Not.LazyLoad();
        Id(s => s.Id, "sampleID").GeneratedBy.Native();
        References<Sample>(s => s.ParentSample, "parentSampleID").NotFound.Ignore();

Столбец parentSampleID должен быть равен 0, когда такого объекта не существует.

Я понял, мне нужно только сделатьгрязные хаки при вставке и обновлении (возможно, в моем случае только при вставке).

При вставке я хочу создать поддельный прокси, но код в [2] загружает объект из БД (возможно, для использованияНулевой объект ?!).

Вставить грязный хак:

        public override object[] GetPropertyValuesToInsert(object entity, IDictionary mergeMap, ISessionImplementor session) {
        var values = base.GetPropertyValuesToInsert(entity, mergeMap, session);

        //dirty hack 1
        for(int i = 0; i < values.Length; i++) {
            if(values[i] == null && typeof(IEntity).IsAssignableFrom(getters[i].ReturnType)) {
                values[i] = ((ISession)session).Load(getters[i].ReturnType, 0);
            }
        }
        return values;
    }

Я попытался создать фальшивый прокси вместо того, чтобы сделать выше:

        public override object[] GetPropertyValuesToInsert(object entity, IDictionary mergeMap, ISessionImplementor session) {
        var values = base.GetPropertyValuesToInsert(entity, mergeMap, session);

        //dirty hack 1
        for(int i = 0; i < values.Length; i++) {
            if(values[i] == null && typeof(IEntity).IsAssignableFrom(getters[i].ReturnType)) {
                //values[i] = ((ISession)session).Load(getters[i].ReturnType, 0);
                values[i] = CreateFakeProxy(i);
            }
        }
        return values;
    }

    private object CreateFakeProxy(int i) {
        object proxy;
        using(var sessionImplementor = _sessionFactory.OpenSession()) {
            proxy = _sessionFactory
                .GetEntityPersister(getters[i].ReturnType.FullName)
                .CreateProxy(0, (ISessionImplementor)sessionImplementor);
        }
        return proxy;
    }

Тогда я получаюисключение nullref для _sessionfactory, установленное в ctor:

        private readonly ISessionFactoryImplementor _sessionFactory;

    public NullableTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity)
        : base(entityMetamodel, mappedEntity) {
            _sessionFactory = entityMetamodel.SessionFactory;

    }

Есть идеи, как этого добиться?

1 Ответ

1 голос
/ 11 июля 2012

Простое решение - добавить следующий прослушиватель preinsert и preupdate.

public class NullToZeroEventListener : AuditEventListener, IPreInsertEventListener, IPreUpdateEventListener
{
    public bool OnPreInsert(PreInsertEvent @event) {
        ZeroNullIds(@event.State, @event.Persister.PropertyNames);
        return false;
    }

    public bool OnPreUpdate(PreUpdateEvent @event) {
        ZeroNullIds(@event.State, @event.Persister.PropertyNames);
        return false;
    }

    protected internal void ZeroNullIds(Object[] state, string[] propertyNames) {
        for(int i = 0; i < propertyNames.Length; i++) {
            if(state[i] != null || propertyNames[i].EndsWith("ID")) continue;
            state[i] = 0;
        }
    }
}

При отображении обязательно игнорируйте 0 идентификаторов, например: References<User>(s => s.User, "userID").NotFound.Ignore().LazyLoad();

В вашей сессионной фабрикедобавьте прослушиватель для событий preinsert и preupdate (сначала показанных здесь):

           .ExposeConfiguration(c =>
            {
                if(!c.EventListeners.PreInsertEventListeners.Any()) {
                    c.AppendListeners(ListenerType.PreInsert, new IPreInsertEventListener[] { new NullToZeroEventListener() });
                }
            });
...