Как сделать так, чтобы NHibernate сохранял значение свойства String.Empty как NULL - PullRequest
2 голосов
/ 07 апреля 2010

У меня есть довольно простой класс, который я хочу сохранить в SQL Server через NHibernate (с отображениями Fluent).Класс состоит в основном из необязательных строковых полей.

Моя проблема в том, что я по умолчанию задаю для полей класса значение string.empty, чтобы избежать исключений NullRefExceptions, и когда NHibernate сохраняет строку в базе данных, каждый столбец содержит пустую строку вместо нуля.

Вопрос: Есть ли у меня способ заставить NHibernate автоматически сохранять ноль, когда свойство строки является пустой строкой?Или мне нужно засорять мой код проверками if (string.empty)?

Ответы [ 3 ]

7 голосов
/ 07 апреля 2010

Вы можете сделать это с UserType.Я пришел к выводу, что нулевые строки бесполезны (и боль в шее) в моих бизнес-классах, поэтому я преобразую все столбцы базы данных, содержащие пустые строки, в пустую строку и наоборот.

Свободное использование:

Map(x => x.MiddleName).CustomType(typeof(NullableString));

/// <summary>
/// UserType for string properties that are database nullable. Using this type
/// will substitue empty string for null when populating object properties
/// and null for empty string in database operations.
/// </summary>
/// <example>
/// Map(x => x.MiddleName).Length(30).Nullable().CustomType(typeof(NullableString));
/// </example>
public class NullableString : IUserType
{
    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.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var valueToGet = NHibernateUtil.String.NullSafeGet(rs, names[0]);
        return valueToGet ?? string.Empty;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var stringObject = value as string;
        object valueToSet = string.IsNullOrEmpty(stringObject) ? null : stringObject;
        NHibernateUtil.String.NullSafeSet(cmd, valueToSet, index);
    }

    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 DeepCopy(cached);
    }

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

    public SqlType[] SqlTypes
    {
        get
        {
            return new[] { new SqlType(DbType.String)};
        }
    }

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

    public bool IsMutable
    {
        get { return false; }
    }
}
5 голосов
/ 07 апреля 2010

NHibernate делает то, что вы просите его сделать. С одной стороны вы говорите, что пытаетесь избежать NullReferenceException, с другой стороны вы пытаетесь сохранить NULL в базе данных, когда значение не равно нулю. Это звучит для меня как противоречие. Вместо того чтобы пытаться обойти эту функциональную ошибку, попробуйте либо разрешить нулевые значения (и проверить данные для предотвращения NRE), либо не разрешать нулевые значения.

Если есть особый случай, который вы хотите покрыть пустыми полями, а не пустыми полями, подумайте о том, чтобы прочитать правильные данные (и не инициализируйте до String.Empty). Если вы обрабатываете пустую строку, равную нулевому значению в этой базе данных, просто инициализируйте все поля пустой строкой, чтобы сделать ее простой и последовательной.

1 голос
/ 07 апреля 2010

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

public static class StringExtensions
{
    public static string NullIfEmpty(this string s)
    {
        return string.IsNullOrEmpty(s) ? null : s;
    }
}

Тогда напишите свой класс сущности так:

public class MyEntity
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value.NullIfEmpty(); }
    }
}

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

Использование пользовательского типа тоже работает; однако, мне всегда кажется, что это «аннулирующее» поведение должно быть поведением сущности , а не mapper , и что у самой сущности должен быть контракт, который говорит Я игнорирую пустые строки. "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...