NHibernate ICompositeUserType 拆分字符串列

NHibernate ICompositeUserType split string columns

我将为字符串 属性 实现一个 ICompositeUserType,它被分成 4 列,每列 2000 个字符(在旧的 oracle 数据库中,以避免 CLOB/LONG 字段)。 实现接口似乎是个好主意,但我无法理解 SetPropertyValue 方法。它不接受类型化或字符串值。我需要它是可变的,所以我需要实现这个方法。

我可以有一个非持久性 属性 来封装拆分和连接到 x 个持久性属性,但我想要更透明的东西。

我发现了类似的问题,但 none 的回复符合我的预期。

-- 更新--

我上传了一些代码来为问题添加上下文:

数据库:

...
Value VARCHAR2(2000 BYTE)
Value2 VARCHAR2(2000 BYTE)
Value3 VARCHAR2(2000 BYTE)
Value4 VARCHAR2(2000 BYTE)
Value5 VARCHAR2(2000 BYTE)
...

HBM:

<property name="Value" type="MyAssembly.NHibernateUtils.Types.MultiColumnJoinedUserType, MyAssembly">
  <column name="DFM_Value"/>
  <column name="DFM_Value2"/>
  <column name="DFM_Value3"/>
  <column name="DFM_Value4"/>
  <column name="DFM_Value5"/>
</property>    

CLASS:

    public virtual string Value { get; set; }

MultiColumnJoinedUserType:

    /// <summary>
    /// Set the value of a property
    /// </summary>
    /// <param name="component">an instance of class mapped by this "type"</param>
    /// <param name="property"></param>
    /// <param name="value">the value to set</param>
    public void SetPropertyValue(object component, int property, object value) { ... }

在我的 class 中,方法的组件字段是一个字符串,因此在不更改引用的情况下不可能更改其值,因为字符串作为值而不是我需要的引用传递。

ICompositeUserType 通常用于您在 .Net 中拥有多个属性的情况(例如 "component")。这里有一个 Money class 的例子:http://geekswithblogs.net/opiesblog/archive/2006/08/05/87218.aspx

由于您在 .Net 中只有一个简单的值,您应该改为实现 IUserType,这仍然允许您在数据库中使用多个列。

我在这个问题上花了几个小时,尝试了各种解决方案:

  • 在 ICompositeUserType 中使用字符串[] 而不是字符串
  • 使用 IUserType 而不是 ICompositeUserType

两者都在 Oracle 中工作,但在 SQL(我需要兼容性)中,空值被设置为空值的默认值。

log4net 中的 NHibernate 跟踪:

INSERT INTO VALUETABLE (HDF_Value1, HDF_Value2, HDF_Value3, HDF_Value4, HDF_Value5) VALUES (@p1, @p2, @p3, @p4, @p5); select SCOPE_IDENTITY(); @p1 = NULL [Type: String (4000)], @p2 = NULL [Type: String (4000)], @p3 = NULL [Type: String (4000)], @p4 = NULL [Type: String (4000)], @p5 = NULL [Type: String (4000)]

但是在 SQLProfiler 中:

exec sp_executesql N'INSERT INTO VALUETABLE (HDF_Value1, HDF_Value2, HDF_Value3, HDF_Value4, HDF_Value5) VALUES (@p1, @p2, @p3, @p4, @p5); select SCOPE_IDENTITY()',N'@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000),@p4 nvarchar(4000),@p5 nvarchar(4000)',@p1=default,@p2=default,@p3=default,@p4=default,@p5=default

我在 nullsafeset 上尝试了各种代码(使用 DBNull、string.NullSafeSet、...),但对我没有任何作用。我不能浪费更多的时间,最后我实现了最简单的解决方案,映射对象上的 5 个 "hidden" 属性和一个拆分和连接值的 "virtual" 属性,它不是非常透明,但按预期工作:

    public virtual string _Value1 { get; set; }
    public virtual string _Value2 { get; set; }
    public virtual string _Value3 { get; set; }
    public virtual string _Value4 { get; set; }
    public virtual string _Value5 { get; set; }

    public virtual string Value
    {
        get
        {
            // JOIN VALUES FROM 5 _Value properties
        }
        set
        {
            // SPLIT VALUE INTO 5 _Value properties
        }
    }

这一刻对我来说已经足够了。

字符串不可变。您可以安全地忽略 SetPropertyValue。我已经在我的不可变用户类型中实现了 GetPropertyValue,我认为它被调用了。

    public bool IsMutable
    {
        get { return false; }
    }

    public void SetPropertyValue(object component, int property, object value)
    {
      throw new NotSupportedException("Something goes wrong here");
    }


    public object GetPropertyValue(object component, int property)
    {
      var stringComponent = (string)component;
      maxLengthToRead = Math.Min(2000, stringComponent.Length - property * 2000);
      if (maxLengthToRead <= 0) return string.Empty;

      return stringComponent.Substring(property * 2000, maxLengthToRead);
    }