NHibernate,试图将对象作为字符串存储在数据库中
NHibernate, trying to store an object as a string in 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");
这就是我得到的
An unhandled exception occurred while processing the request.
InvalidCastException: Unable to cast object of type CityList to type System.String
NHibernate.Type.AbstractStringType.Set(DbCommand cmd, object value, int index, ISessionImplementor session)PropertyValueException:
Error dehydrating property value for CityList
Command.Stack.Adapters.Base.UnitOfWork.IUnitOfWork.CommitAsync(CancellationToken
cancellationToken)
为什么我会得到这个?以及如何解决?
需要说明的是,这不是您问题的确切答案,但希望提供替代方法来实现相同的目的。我们创建了名为 JsonMappable Type 的自定义 IUserType。这种类型将保存到DB中的数据序列化和反序列化为JSON字符串,需要覆盖NullSafeGet和Set,然后在映射文件中很容易这样映射,
Property(p => p.UserAvailability, m =>
{
m.Type<JsonMappableType<UserAvailability>>();
});
这个link提供了如何实现iusertype
How to implement correctly 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;
}
}
我想要实现的是以某种形式序列化一个对象并将其存储在数据库中,然后重新创建它。
这是结构:我正在使用 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");
这就是我得到的
An unhandled exception occurred while processing the request. InvalidCastException: Unable to cast object of type CityList to type System.String
NHibernate.Type.AbstractStringType.Set(DbCommand cmd, object value, int index, ISessionImplementor session)PropertyValueException: Error dehydrating property value for CityList Command.Stack.Adapters.Base.UnitOfWork.IUnitOfWork.CommitAsync(CancellationToken cancellationToken)
为什么我会得到这个?以及如何解决?
需要说明的是,这不是您问题的确切答案,但希望提供替代方法来实现相同的目的。我们创建了名为 JsonMappable Type 的自定义 IUserType。这种类型将保存到DB中的数据序列化和反序列化为JSON字符串,需要覆盖NullSafeGet和Set,然后在映射文件中很容易这样映射,
Property(p => p.UserAvailability, m =>
{
m.Type<JsonMappableType<UserAvailability>>();
});
这个link提供了如何实现iusertype
How to implement correctly 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;
}
}