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

发布于 2024-08-27 23:39:10 字数 265 浏览 4 评论 0原文

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

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

问题:有没有办法让NHibernate在字符串属性为空字符串时自动保存null?或者我是否需要在代码中添加 if (string.empty) 检查?

I have a fairly simple class that I want to save to SQL Server via NHibernate (w/ Fluent mappings). The class is made up mostly of optional string fields.

My problem is I default the class fields to string.empty to avoid NullRefExceptions and when NHibernate saves the row to the database each column contains an empty string instead of null.

Question: Is there a way for me to get NHibernate to automatically save null when the string property is an empty string? Or do I need to litter my code with if (string.empty) checks?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

饮惑 2024-09-03 23:39:10

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

You can do this with a UserType. I've come to the conclusion that null strings are useless (and a pain in the neck) in my business classes so I convert all nullable string database columns to empty string and vice-versa.

Fluent usage is:

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; }
    }
}
〃安静 2024-09-03 23:39:10

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

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

NHibernate is doing what you ask it to do. At one end you are saying that you try to avoid NullReferenceException, at the other end you are trying to save NULL in the database when a value is not null. That sounds to me like a contradiction. Instead of trying to workaround this feature bug, try to either allow nulls (and check the data to prevent the NRE's) or don't allow nulls.

If there's a special case you want to cover with NULL fields vs empty fields, consider reading the correct data (and don't init to String.Empty). If you treat an empty string equal to a null value in that database, just initialize all fields to the empty string to keep it easy and consistent.

淡淡離愁欲言轉身 2024-09-03 23:39:10

我不会说你需要在你的代码中添加检查。我使用单个扩展方法:

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

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

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

I wouldn't say that you need to litter your code with checks. I use a single extension method:

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

Then write your entity class this way:

public class MyEntity
{
    private string name;

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

I think it's best that you indicate explicitly that you want this behaviour, because in many cases an empty string might be a valid value in the database.

Using a custom type works too; however, it always feels to me like this "nullifying" behaviour ought to be a behaviour of the entity and not the mapper, and that the entity itself should have a contract that says "I ignore empty strings."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文