IUserType是否能够将一个值转换为null,并在生成的查询中输出为IS NULL?

huangapple go评论66阅读模式
英文:

NHibernate: Is it possible for IUserType to convert a value to null and have it output as IS NULL in the resulting query?

问题

我们正在使用NHibernate作为我们的ORM。我们有一张表,其中一个列上映了一个自定义的IUserType。IUserType的目的是,根据我们使用的连接类型,该值可能为null或仅为空字符串。

因此,当我们运行此查询时,根据底层数据存储,IUserType将空字符串转换为null:

Session.QueryOver<MyTable>().Where(t=>t.MyColumn == string.Empty).ToList()

这将创建以下查询:

select * from MyTable where MyColumn = NULL

查看NHibernate代码,有以下代码:

SqlStringBuilder sqlBuilder = new SqlStringBuilder(4 * columnNames.Length);
var columnNullness = typedValue.Type.ToColumnNullness(typedValue.Value, criteriaQuery.Factory);

if (columnNullness.Length != columnNames.Length)
{
    throw new AssertionFailure("Column nullness length doesn't match the number of columns.");
}

for (int i = 0; i < columnNames.Length; i++)
{
    if (i > 0)
    {
        sqlBuilder.Add(" and ");
    }

    if (columnNullness[i])
    {
        sqlBuilder.Add(columnNames[i])
                  .Add(Op)
                  .Add(parameters[i]);
    }
    else
    {
        sqlBuilder.Add(columnNames[i])
                  .Add(" is null ");
    }
}
return sqlBuilder.ToSqlString();

但是columnNullness只基于当前值,而不是转换后的值,这是NHibernate代码中的CustomType中的内容:

public override bool[] ToColumnNullness(object value, IMapping mapping)
{
    bool[] result = new bool[GetColumnSpan(mapping)];
    if (value != null)
        ArrayHelper.Fill(result, true);
    return result;
}

是否有办法让IUserType将值转换为null,并使查询输出为IS NULL?

英文:

We are using NHibernate as our ORM. We have a table that one of the columns has a custom IUserType mapped onto it. The purpose of the IUserType is that depending on the type of connection we are using the value might be null or just an empty string.

So when we run this query depending on the underlying data storage the IUserType will convert the empty string to null
Session.QueryOver&lt;MyTable&gt;().Where(t=&gt;t.MyColumn == string.Empty).ToList()
Witch creates this query
select * from MyTable where MyColumn = NULL

Looking at the NHibernate code there is this code

SqlStringBuilder sqlBuilder = new SqlStringBuilder(4 * columnNames.Length);
var columnNullness = typedValue.Type.ToColumnNullness(typedValue.Value, criteriaQuery.Factory);

if (columnNullness.Length != columnNames.Length)
{
	throw new AssertionFailure(&quot;Column nullness length doesn&#39;t match number of columns.&quot;);
}

for (int i = 0; i &lt; columnNames.Length; i++)
{
	if (i &gt; 0)
	{
		sqlBuilder.Add(&quot; and &quot;);
	}

	if (columnNullness[i])
	{
		sqlBuilder.Add(columnNames[i])
				  .Add(Op)
				  .Add(parameters[i]);
	}
	else
	{
		sqlBuilder.Add(columnNames[i])
				  .Add(&quot; is null &quot;);
	}
}
return sqlBuilder.ToSqlString();

but column nullness is just based on the current value not the converted value this is from CustomType in NHibernate code

public override bool[] ToColumnNullness(object value, IMapping mapping)
{
	bool[] result = new bool[GetColumnSpan(mapping)];
	if (value != null)
		ArrayHelper.Fill(result, true);
	return result;
}

Is there anyway to have a IUserType convert a value to null and have the query come out as IS NULL?

答案1

得分: 0

看起来是关于IUserType类型的一个bug(缺失功能)。

在你的情况下,似乎可以基于AbstractStringType实现自定义类型,类似于以下方式:

[Serializable]
public class EmptyAsDbNullStringType : AbstractStringType
{
    public EmptyAsDbNullStringType() : base(new StringSqlType())
    {
    }

    public EmptyAsDbNullStringType(int length) : base(new StringSqlType(length))
    {
    }

    public override string Name => "EmptyAsDbNullString";

    public override void NullSafeSet(DbCommand st, object value, int index, bool[] settable,
        ISessionImplementor session)
    {
        base.NullSafeSet(st, ToDbValue(value), index, settable, session);
    }

    public override object NullSafeGet(DbDataReader rs, string name, ISessionImplementor session)
    {
        return FromDbValue(base.NullSafeGet(rs, name, session));
    }

    public override bool[] ToColumnNullness(object value, IMapping mapping)
    {
        return base.ToColumnNullness(ToDbValue(value), mapping);
    }

    private static object ToDbValue(object value)
    {
        return string.Empty.Equals(value) ? null : value;
    }

    private static object FromDbValue(object value)
    {
        return value ?? string.Empty;
    }
}

你可能需要重写更多的成员以确保它在所有情况下都能正常工作。

英文:

Looks like a bug (missing feature) for IUserType types.

It seems in your case you can implement custom type based on AbstractStringType. Something like:

[Serializable]
public class EmptyAsDbNullStringType : AbstractStringType
{
	public EmptyAsDbNullStringType() : base(new StringSqlType())
	{
	}

	public EmptyAsDbNullStringType(int length) : base(new StringSqlType(length))
	{
	}

	public override string Name =&gt; &quot;EmptyAsDbNullString&quot;;

	public override void NullSafeSet(DbCommand st, object value, int index, bool[] settable,
		ISessionImplementor session)
	{
		base.NullSafeSet(st, ToDbValue(value), index, settable, session);
	}

	public override object NullSafeGet(DbDataReader rs, string name, ISessionImplementor session)
	{
		return FromDbValue(base.NullSafeGet(rs, name, session));
	}

	public override bool[] ToColumnNullness(object value, IMapping mapping)
	{
		return base.ToColumnNullness(ToDbValue(value), mapping);
	}

	private static object ToDbValue(object value)
	{
		return string.Empty.Equals(value) ? null : value;
	}

	private static object FromDbValue(object value)
	{
		return value ?? string.Empty;
	}
}

You might need to override some more members to make it work properly in all cases.

huangapple
  • 本文由 发表于 2023年6月2日 06:39:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76386135.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定