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

时间:2018-12-02 23:12:31

标签: nhibernate

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

这是结构:我正在使用https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/using-conversion-operators进行转换

 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");

这就是我得到的

  

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

类型      

NHibernate.Type.AbstractStringType.Set(DbCommand cmd,对象值,整数索引,ISessionImplementor会话)PropertyValueException:   脱水CityList的属性值时出错   Command.Stack.Adapters.Base.UnitOfWork.IUnitOfWork.CommitAsync(CancellationToken   cancelToken)

我为什么要得到这个?以及如何解决?

2 个答案:

答案 0 :(得分:2)

请明确说明,这不是您所提问题的确切答案,但希望提供替代方法来实现同样的目的。我们创建了名为JsonMappable Type的Custom IUserType。此类型将以JSON字符串形式保存到数据库的数据序列化和反序列化,您需要覆盖NullSafeGet和Set,然后很容易在映射文件中映射它,

        Property(p => p.UserAvailability, m =>
        {
            m.Type<JsonMappableType<UserAvailability>>();
        });

此链接提供了如何实现iusertype

How to implement correctly IUserType?

答案 1 :(得分:0)

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