Вопрос по fluent-nhibernate, nhibernate – Отображение пустых строк в NULL в NHibernate

2

У меня есть БД SQL Server с рекурсивной таблицей:

MyTable:
 ID : string PrimaryKey
 Parent: string references MyTable - NOTNULL !!

и карта с беглым NHibernate для

class MyTable
{
  public virtual string ID {get; set;}
  public virtual MyTable Parent {get; set;}
}

Моя проблема в том, что родительский элемент должен быть нулевым в моем приложении на C #, если столбец Родительский & quot; & quot; (пустая строка) в базе данных и наоборот. К сожалению, я не могу изменить тип столбца, чтобы принять NULL!

Я пытался использовать IEmptyInterceptor, но у меня не получается.

Заранее спасибо,   forki

Ваш Ответ

5   ответов
0

Я попытался реализовать IUserType для моего отображения:

public class MyCustomString : IUserType
{
    public Type ReturnedType
    {
        get { return typeof (MyTable); }
    }

    public SqlType[] SqlTypes
    {
        get { return new[] {NHibernateUtil.String.SqlType}; }
    }    

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        object obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (obj == null) return null;

        var s = (string) obj;

        if (s == "")
            return null;
        using (ISession session = SessionHelper.OpenSession())
        {
            using (session.BeginTransaction())
            {
                return MyTable.Get(session, s);
            }
        }
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        ((IDataParameter) cmd.Parameters[index]).Value = value == null ? 0 : ((MyTable) value).EntryNo;
    }

   ...
}

и изменил отображение на

    public MyTableMap()
    {
        Id(x => x.EntryNo);

        Map(x => x.Parent).CustomTypeIs<MyCustomString>();

        // References() doesn't allow CustomTypeIs()
        // References(x => x.Parent).CustomTypeIs<MyCustomString>();
    }

Кажется, это работает для моего рута - но он всегда открывает сеанс, чтобы получить правильного родителя. И он не ленивый - поэтому он всегда возвращает всех родителей до корня :-(

Это не может быть правильным способом. Я не хочу открывать новый сеанс, но в противном случае я возвращаю строку и получаю ошибку типа времени выполнения.

2

public class NullEventListener : IPreUpdateEventListener, IPreInsertEventListener, IPreLoadEventListener
{
    #region IPreInsertEventListener Members

    public bool OnPreInsert(PreInsertEvent preInsertEvent)
    {
        var instance = preInsertEvent.Entity as MyTable;
        if (instance == null)
            return false;

        if (instance.Parent == null)
            Set(preInsertEvent.Persister, preInsertEvent.State, "Parent", string.Empty);     

        return false;
    }

    #endregion

    #region IPreLoadEventListener Members

    public void OnPreLoad(PreLoadEvent preLoadEvent)
    {
        var instance = preLoadEvent.Entity as MyTable;
        if (instance == null)
            return;

        try
        {
            // this is really messy!!
            var parent = Get(preLoadEvent.Persister, preLoadEvent.State, "Parent") as MyTable;
            if (parent == null || parent.ID == "")
                throw new Exception("Set to null");
        }
        catch (Exception)
        {
            Set(preLoadEvent.Persister, preLoadEvent.State, "Parent", null);
        }

        return;
    }

    #endregion

    #region IPreUpdateEventListener Members

    public bool OnPreUpdate(PreUpdateEvent preUpdateEvent)
    {
        var instance = preUpdateEvent.Entity as MyTable;
        if (instance == null)
            return false;

        if (instance.Parent == null)
            Set(preUpdateEvent.Persister, preUpdateEvent.State, "Parent", string.Empty);     

        return false;
    }

    #endregion

    private static void Set(IEntityPersister persister, object[] state, string propertyName, object value)
    {
        int index = Array.IndexOf(persister.PropertyNames, propertyName);
        if (index == -1)
            return;
        state[index] = value;
    }

    private static object Get(IEntityPersister persister, object[] state, string propertyName)
    {
        int index = Array.IndexOf(persister.PropertyNames, propertyName);
        if (index == -1)
            return null;
        return state[index];
    }
}

Спасибо и всего наилучшего,   forki

5

который выполняет специальную обработку значения NULL.

public MyTableMap()
{
    Id(x => x.EntryNo)
        // Since the PK is a string, it must be assigned by the application.
        .GeneratedBy.Assigned()
        .SetAttribute("type", typeof(SpecialNullValueStringType).AssemblyQualifiedName);

    References(x => x.Parent);
}

public class SpecialNullValueStringType : IUserType
{
    #region IUserType Members
    public bool IsMutable
    {
        get { return false; }
    }

    public Type ReturnedType
    {
        get { return typeof(string); }
    }

    public SqlType[] SqlTypes
    {
        get { return new[] { NHibernateUtil.String.SqlType }; }
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (obj == null)
        {
            return null;
        }

        var value = (string) obj;
        if (String.IsNullOrEmpty(value))
        {
            return null;
        }

        return value;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        if (value == null)
        {
            ((IDataParameter) cmd.Parameters[index]).Value = String.Empty;
        }
        else
        {
            ((IDataParameter) cmd.Parameters[index]).Value = value;
        }
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    public object Disassemble(object value)
    {
        return value;
    }

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }

        if (x == null || y == null)
        {
            return false;
        }

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x == null ? typeof(string).GetHashCode() + 473 : x.GetHashCode();
    }
    #endregion
}
0
Я думаю, что это та же проблема с шаблоном NUll Object. Я не знаю, как преобразовать пустую строку в мой NullObject. forki23
О, да, вы правы, вы попадаете в бесконечный цикл нулевого объекта, содержащегося в нулевом объекте, содержащемся в нулевом объекте. , , aaahhh !!!!
Или я должен сохранить объект Null в базе данных? forki23
1

IUserType который будет конвертировать пустую строку вnullс и наоборот. Два способа обратить внимание на этоNullSafeGet а такжеNullSafeSet.

Не уверен, однако, как пользовательские типы интегрируются с Fluent NHibernate.

Привет, Эрик и Джеймс, не могли бы вы сказать мне, что я делаю неправильно? Пожалуйста, смотрите код в ответе 2. Спасибо, Форки forki23
Я попробовал это. Но, к сожалению, у меня это не получилось. Должен ли я реализовать IUserType для класса MyTable? forki23
Ваш класс домена не должен реализовывать интерфейс IUserType, вместо этого вы должны создать отдельный класс пользовательских типов на уровне доступа к данным, который затем будет использоваться в отображении. Таким образом, ваш уровень домена по-прежнему не будет необходим для доступа к данным. слой. Чтобы указать типы пользователей в отображении Fluent NHibernate, используйте метод .CustomTypeIs & lt; MyUserType & gt; ().
IUserType, безусловно, путь. Создайте реализацию этого интерфейса отдельно от всего остального, которая будет использоваться для преобразования пустых строк в пустые и наоборот. Затем вы указываете эту реализацию в беглых сопоставлениях, используя CustomTypeIs, как показал Эрик.

Похожие вопросы