如何在Fluent NHibernate中映射IDictionary<string, object>?

7

我希望将用户偏好存储为键值对的集合,其中值可以是整数、布尔值或字符串。

有几种实现方法,但我认为最方便的方法是像这样:

public class User
{
    public virtual IDictionary<string, object> Preferences { get; set; }
}

使用方式如下:

user.Preferences["preference1"] = "some value";
user.Preferences["preference2"] = 10;
user.Preferences["preference3"] = true;

var pref = (int)user.Preferences["preference2"];

我不确定如何在Fluent NHibernate中映射此内容,但我认为这是可能的。通常,您可以将较简单的Dictionary<string, string>映射为:
HasMany(x => x.Preferences)
    .Table("Preferences")
    .AsMap("preferenceName")
    .Element("preferenceValue");

但是对于类型为“object”的情况,NHibernate并不知道如何处理。我想可以创建一个自定义的UserType,将“object”分解为表示其类型的字符串和表示其值的字符串。我们将拥有一个类似于下面的表:

Table Preferences
    userId (int)
    preferenceName (varchar)
    preferenceValue (varchar)
    preferenceValueType (varchar)

然后,Hibernate 的映射应该如下所示:

<map name="Preferences" table="Preferences"> 
  <key column="userId"></key> 
  <index column="preferenceName" type="String" />
  <element type="ObjectAsStringUserType, Assembly">
    <column name="preferenceValue" /> 
    <column name="preferenceValueType"/> 
  </element> 
</map> 

我不确定如何在Fluent NHibernate中进行映射。

也许有更好的方法来解决这个问题,或者我应该使用IDictionary<string, string>。你有什么想法吗?

1个回答

6

我认为IDictionary<string,string>会更容易。不过这是代码:

        HasMany(u => u.Preferences)
            .Table("Preferences")
            .AsMap("preferenceName")
            .Element("preferenceType", e => e.Column("preferenceValue").Type<ObjAsStringUserType>());

class ObjAsStringUserType : ImmutableUserType
{
    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var type = (string)NHibernateUtil.String.NullSafeGet(rs, names[0]);
        var value = (string)NHibernateUtil.String.NullSafeGet(rs, names[1]);

        switch (type)
        {
            case "boolean":
                return bool.Parse(value);
                ...
            default:
                return null;
                break;
        }
    }

    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var type = value.GetType().Name;
        var valuestring = value.ToString(CultureInfo.InvariantCulture);

        NHibernateUtil.String.NullSafeSet(cmd, type, index);
        NHibernateUtil.String.NullSafeSet(cmd, valuestring, index + 1);
    }

    public override Type ReturnedType
    {
        get { return typeof(object); }
    }

    public override SqlType[] SqlTypes
    {
        get { return new []
        {
            SqlTypeFactory.GetString(length: 255),  // preferenceType
            SqlTypeFactory.GetString(length: 255),  // preferenceValue
        };
        }
    }
}

谢谢你的帮助,伙计,非常准确。 - jolySoft
什么是ImmutableUserType?我在NHibernate或FNH中找不到它的参考。 - Jeff Doolittle
@JeffDoolittle 这是我自己实现的基础类型,实现了NH的IUseryType接口。我在这里发布了它 https://dev59.com/slvUa4cB1Zd3GeqPsEyK#7484139 - Firo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接