使用NHibernate映射字符串集合

14

我有一个领域类,其中包含一个 IList<string> 属性,我想将其映射到一个只包含单个数据值的表中(即它具有一个ID,一个指向领域实体表的外键ID和一个varchar数据列)。

但我一直收到以下错误:

关联引用未映射的类: System.String

如何将表映射到一个字符串集合?


这没有任何问题。你只是使用了一对多的映射,这只适用于实体列表。看看Derek和Frederik的答案。 - Stefan Steinegger
3个回答

22

我遇到了类似的情况,发现可以将字符串集合映射起来。请注意,您需要将这些字符串映射为值对象。

以下是我的代码:

public class Chapter
{
    private ISet<string> _synonyms = new HashedSet<string>();

    public ReadOnlyCollection<string> Synonyms
    {
       get { return new List<string>(_synonyms).AsReadOnly(); }
    }
}

映射:

<class name="Chapter" table="Chapter">
   <set name="Synonyms" table="ChapterSynonyms">
       <key column="ChapterId" />
       <element column="ChapterCode" type="string" />
   </set>
</class>

10
最近又遇到了这个问题,以下是我根据你的XML映射所使用的FluentNHibernate映射: mapping.HasMany(x => x.Synonyms).AsBag().Element("ChapterCode", m => m.Type<string>()); - roryf
哈希集合不应该是“HashShet”吗? - jvdveuten
1
@roryf 你正在使用一个 Bag,应该使用 Set。正确的代码应该是:HasMany(x=>x.Synonyms).Table("Synonyms").AsSet().Element("ChapterCode", m=>m.Type<string>().Not.Nullable()); - jvdveuten
不应该将HashedSet误认为是HashSet。HashedSet是Iesi.Collections类型,在MS创建HashSet类型之前,NHibernate使用了它。虽然示例代码也可以使用MS的HashSet<T>,但使用HashedSet完全合法。 - Frederik Gheysels

8
除非我错了,您可以这样做:
<bag name="Identities" access="property">
  <key column="accountId"/>
  <element column="identity" type="string"/>
</bag>

身份识别是一个IList<string>


1

您可以使用IUserType来实现此操作:

public class DelimitedList : IUserType
{
    private const string delimiter = "|";

    public new bool Equals(object x, object y)
    {
        return object.Equals(x, y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var r = rs[names[0]];
        return r == DBNull.Value 
            ? new List<string>()
            : ((string)r).SplitAndTrim(new [] { delimiter });
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        object paramVal = DBNull.Value;
        if (value != null)
        {
            paramVal = ((IEnumerable<string>)value).Join(delimiter);
        }
        var parameter = (IDataParameter)cmd.Parameters[index];
        parameter.Value = paramVal;
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    public object Disassemble(object value)
    {
        return value;
    }

    public SqlType[] SqlTypes
    {
        get { return new SqlType[] { new StringSqlType() }; }
    }

    public Type ReturnedType
    {
        get { return typeof(IList<string>); }
    }

    public bool IsMutable
    {
        get { return false; }
    }
}

然后将IList<string>属性定义为type="MyApp.DelimitedList, MyApp"。

注意:SplitAndTrim是我创建的具有各种重载的字符串扩展。以下是核心方法:

public static IList<string> SplitAndTrim(this string s, StringSplitOptions options, params string[] delimiters)
    {
        if (s == null)
        {
            return null;
        }
        var query = s.Split(delimiters, StringSplitOptions.None).Select(x => x.Trim());
        if (options == StringSplitOptions.RemoveEmptyEntries)
        {
            query = query.Where(x => x.Trim() != string.Empty);
        }
        return query.ToList();
    }

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