如何让NHibernate将String.Empty属性值保持为NULL

时间:2010-04-07 12:57:16

标签: .net nhibernate fluent-nhibernate

我有一个相当简单的类,我希望通过NHibernate(w / Fluent映射)保存到SQL Server。该类主要由可选的字符串字段组成。

我的问题是我将类字段默认为string.empty以避免NullRefExceptions,当NHibernate将行保存到数据库时,每列都包含一个空字符串而不是null。

问题:当string属性为空字符串时,有没有办法让NHibernate自动保存null?或者我需要使用if(string.empty)检查来丢弃我的代码吗?

3 个答案:

答案 0 :(得分:7)

您可以使用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; }
    }
}

答案 1 :(得分:5)

NHibernate正在做你要求它做的事情。一方面,你说你试图避免NullReferenceException,另一方面,当一个值不为空时,你试图在数据库中保存NULL。这听起来像是一个矛盾。而不是尝试解决此功能错误,尝试允许空值(并检查数据以防止NRE)或不允许空值。

如果您想要覆盖NULL字段与空字段的特殊情况,请考虑读取正确的数据(并且不要初始化为String.Empty)。如果将空字符串视为等于该数据库中的空值,则只需将所有字段初始化为空字符串,以使其保持简单和一致。

答案 2 :(得分:1)

我不会说你需要用支票乱丢你的代码。我使用一种扩展方法:

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

我认为最好明确指出您想要这种行为,因为在许多情况下,空字符串可能是数据库中的有效值。

使用自定义类型也可以;但是,我总觉得这种“无效”行为应该是实体而不是映射器的行为,并且实体本身应该有一个合同,说“我忽略空字符串。”