NHibernate,尝试将对象作为字符串存储在DB中

NHibernate,尝试将对象作为字符串存储在DB中,nhibernate,Nhibernate,我试图实现的是以某种形式序列化对象并将其存储在db中,然后重新创建它 这是结构:我正在使用转换 public class Order : AggregateRoot { private string _cityList; public virtual CityList CityList { get => (CityList)_cityList; } } public class CityList : ValueObject { private stri

我试图实现的是以某种形式序列化对象并将其存储在db中,然后重新创建它

这是结构:我正在使用转换

 public class Order : AggregateRoot
 {
    private string _cityList;
    public virtual CityList CityList { get => (CityList)_cityList; }
 }

 public class CityList : ValueObject
 {
     private string _cities { get; }

     public CityList(string cities)
     {
         _cities = cities;
     }

     public static explicit operator CityList(string cityList)
     {
         return new CityList(cityList);
     }

     public static implicit operator string(CityList cityList)
     {
         return (string)cityList;
     }
  }
这是配置

 mapping
        .Map(Reveal.Member<Order>("CityList"))
        .CustomType("string")
        .Column("CityList");
映射
.Map(显示成员(“城市列表”))
.CustomType(“字符串”)
。栏(“城市列表”);
这就是我得到的

处理请求时发生未处理的异常。 InvalidCastException:无法将CityList类型的对象强制转换为System.String类型

NHibernate.Type.AbstractStringType.Set(DbCommand cmd、对象值、int索引、ISessionImplementor会话)PropertyValueException: 提取CityList的属性值时出错 Command.Stack.Adapters.Base.UnitOfWork.IUnitOfWork.CommitAsync(CancellationToken 取消令牌)


为什么我会得到这个?如何解决这个问题呢?

只是想澄清一下,这并不是你问题的确切答案,但我想给出实现同样目标的替代方法。我们创建了名为JsonMappable类型的自定义IUserType。这种类型将作为JSON字符串保存到DB中的数据序列化和反序列化,您需要覆盖NullSafeGet和Set,然后在映射文件中这样映射它就很容易了

        Property(p => p.UserAvailability, m =>
        {
            m.Type<JsonMappableType<UserAvailability>>();
        });
Property(p=>p.UserAvailability,m=>
{
m、 类型();
});
此链接提供如何实现iusertype


您可以使用IUserType接口

[Serializable]
public class AsClobStringUserType<T> : IUserType
{
    public AsClobStringUserType()
    {
        
    }

    /// <summary>
    /// The type returned by NullSafeGet()
    /// </summary>
    Type IUserType.ReturnedType => typeof(T);
    bool IUserType.IsMutable => false;
    SqlType[] IUserType.SqlTypes => new SqlType[] { new StringClobSqlType() };

    /// <summary>
    /// Used for casching, the object is immutable, just return 
    /// </summary>
    /// <param name="cached"></param>
    /// <param name="owner"></param>
    /// <returns></returns>
    object IUserType.Assemble(object cached, object owner)
    {
        return cached;
    }

    /// <summary>
    /// Deep copy the Translation by creating a new instance with the same contents
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    object IUserType.DeepCopy(object value)
    {
        if (value == null) return null;

        if (value.GetType() != typeof(T)) return null;

        string jsonString = JsonSerializationService.Instance.Serialize((T)value);

        return JsonSerializationService.Instance.Deserialize<T>(jsonString);
    }

    /// <summary>
    /// Used for casching, the object is immutable, just return 
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    object IUserType.Disassemble(object value)
    {
        return value;
    }

    /// <summary>
    /// Use json string to check the equality
    /// </summary>
    /// <param name="object1"></param>
    /// <param name="object2"></param>
    /// <returns></returns>
    bool IUserType.Equals(object object1, object object2)
    {
        if (ReferenceEquals(object1, null) && ReferenceEquals(object2, null)) return true;

        if (ReferenceEquals(object1, null) || ReferenceEquals(object2, null)) return false;

        return JsonSerializationService.Instance.Serialize((T)object1) == JsonSerializationService.Instance.Serialize((T)object2);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="object"></param>
    /// <returns></returns>
    int IUserType.GetHashCode(object @object)
    {
        if (@object != null && @object.GetType() == typeof(T))
        {
            return JsonSerializationService.Instance.Serialize((T)@object).GetHashCode();
        }

        return @object.GetHashCode();
    }

    #region Serialization
    /// <summary>
    /// Retrieve an instance of the mapped class from.
    /// </summary>
    /// <remarks>
    /// Should handle possibility of null values.
    /// </remarks>
    /// <param name="owner">the entity to work with. (serialized object)</param>
    object IUserType.NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
    {
        /// => Translation should be stored in single column 
        if (names.Length != 1) throw new InvalidOperationException("Translation should be stored in single column.");

        string value = rs[names[0]] as string;

        if (!string.IsNullOrWhiteSpace(value)) return JsonSerializationService.Instance.Deserialize<T>(value);

        return null;
    }

    /// <summary>
    /// Write an instance of the mapped class to a prepared statement.
    /// </summary>
    /// <remarks>
    /// Should handle possibility of null values.
    /// </remarks>
    /// <param name="cmd">the object to be serialized and written to persistence store.</param>
    /// <param name="value">the object to be serialized and written to persistence store.</param>
    void IUserType.NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
    {
        DbParameter parameter = cmd.Parameters[index];

        if (value == null)
        {
            parameter.Value = DBNull.Value;
        }
        else
        {
            parameter.Value = JsonSerializationService.Instance.Serialize(value);
        }
    }
    #endregion

    /// <summary> 
    /// As our object is immutable just return the original
    /// </summary>
    /// <param name="original"></param>
    /// <param name="target"></param>
    /// <param name="owner"></param>
    /// <returns></returns>
    object IUserType.Replace(object original, object target, object owner)
    {
        return original;
    }
}
[可序列化]
公共类AsClobStringUserType:IUserType
{
公共AsClobStringUserType()
{
}
/// 
///NullSafeGet()返回的类型
/// 
类型IUserType.ReturnedType=>typeof(T);
bool IUserType.IsMutable=>false;
SqlType[]IUserType.SqlTypes=>newsqltype[]{new StringClobSqlType()};
/// 
///用于级联,对象是不可变的,只需返回
/// 
/// 
/// 
/// 
对象IUserType.Assemble(对象缓存,对象所有者)
{
返回缓存;
}
/// 
///通过创建具有相同内容的新实例来深度复制翻译
/// 
/// 
/// 
对象IUserType.DeepCopy(对象值)
{
if(value==null)返回null;
if(value.GetType()!=typeof(T))返回null;
字符串jsonString=JsonSerializationService.Instance.Serialize((T)值);
返回JsonSerializationService.Instance.Deserialize(jsonString);
}
/// 
///用于级联,对象是不可变的,只需返回
/// 
/// 
/// 
对象IUserType.DISABLANCE(对象值)
{
返回值;
}
/// 
///使用json字符串检查相等性
/// 
/// 
/// 
/// 
bool IUserType.Equals(对象object1,对象object2)
{
if(ReferenceEquals(object1,null)和&ReferenceEquals(object2,null))返回true;
if(ReferenceEquals(object1,null)| | ReferenceEquals(object2,null))返回false;
返回JsonSerializationService.Instance.Serialize((T)object1)==JsonSerializationService.Instance.Serialize((T)object2);
}
/// 
/// 
/// 
/// 
/// 
intIUSERTYPE.GetHashCode(object@object)
{
if(@object!=null&&@object.GetType()==typeof(T))
{
返回JsonSerializationService.Instance.Serialize((T)@object.GetHashCode();
}
返回@object.GetHashCode();
}
#区域序列化
/// 
///从中检索映射类的实例。
/// 
/// 
///应该处理空值的可能性。
/// 
///要使用的实体。(序列化对象)
对象IUserType.NullSafeGet(DbDataReader、字符串[]名称、ISessionImplementor会话、对象所有者)
{
///=>翻译应存储在单列中
如果(names.Length!=1)抛出新的InvalidOperationException(“翻译应存储在单列中”);
字符串值=rs[名称[0]]作为字符串;
如果(!string.IsNullOrWhiteSpace(value))返回JsonSerializationService.Instance.Deserialize(value);
返回null;
}
/// 
///将映射类的实例写入准备好的语句。
/// 
/// 
///应该处理空值的可能性。
/// 
///要序列化并写入持久性存储的对象。
///要序列化并写入持久性存储的对象。
void IUserType.NullSafeSet(DbCommand cmd、对象值、int索引、ISessionImplementor会话)
{
DbParameter=cmd.Parameters[index];
如果(值==null)
{
parameter.Value=DBNull.Value;
}
其他的
{
parameter.Value=JsonSerializationService.Instance.Serialize(值);
}
}
#端区
///  
///因为我们的对象是不可变的,所以只需返回原始对象
/// 
/// 
/// 
/// 
/// 
对象IUserType.Replace(对象原始、对象目标、对象所有者)
{
归还原件;
}
}

我无法让您的
城市列表
-->
字符串
操作员独立工作。我不得不把它改成:
returncitylist.\u cities以使其工作。尽管如此,我得到的异常是
StackOverflowException
not
InvalidCastException
。但是值得一看的是,抛出异常的NH代码执行以下操作:
if(parameter.Size>0&((string)value).Length>parameter.Size)
,因此强制转换需要工作。