You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用FluentNHibernate将电子邮件地址集合映射为ICollection<EmailAddress>而非ICollection<string>

如何使用FluentNHibernate将电子邮件地址集合映射为ICollection而非ICollection

兄弟,我太懂你为了避免邮箱大小写踩坑写这个EmailAddress类的痛苦了!之前我在FluentNHibernate映射自定义值对象集合的时候也栽过一模一样的跟头,咱们来一步步解决这个映射异常的问题。

先说说你出错的根源

你在映射里用了.CollectionType<EmailAddressType>(),这是找错了地方!EmailAddressType是用来把单个数据库字符串列转换成EmailAddress对象的单个值类型映射,而不是整个集合的类型。NHibernate看到你这么配置,完全搞不懂怎么把集合里的字符串元素转成EmailAddress,自然就抛出“无法确定类型”的异常了。

正确的映射写法

咱们把集合映射的配置改一下,核心是告诉NHibernate:集合里的每个EmailAddress元素,要通过EmailAddressType来和数据库的EmailAddress字符串列做转换。修正后的PersonInfoMap代码如下:

public class PersonInfoMap : ClassMap<PersonInfo>
{
    public PersonInfoMap()
    {
        Schema("dbo");
        Table("Person");
        Id(person => person.Id);
        ReadOnly();

        HasMany(person => person.Emails)
            .Schema("dbo")
            .Table("PersonEmailView")
            .KeyColumn("PersonId")
            .Access.CamelCase(Prefix.Underscore)
            .AsSet()
            // 关键修改:在Element中指定元素的自定义类型
            .Element("EmailAddress", element => element.Type<EmailAddressType>())
            // 因为是从视图读取,加上只读配置更稳妥,避免NHibernate尝试写操作
            .ReadOnly();
    }
}

还有个容易忽略的大坑!你的EmailAddress类有个隐患

我注意到你EmailAddress的GetHashCode()方法是直接用value.GetHashCode(),这会导致严重问题:比如Foo@Bar.com和foo@bar.com的哈希码是不同的,但你的Equals方法认为它们是相等的。而你用了.AsSet()(集合是HashSet),HashSet依赖哈希码的一致性,这会导致同一个邮箱的大小写不同版本被当成不同元素存入集合,完全违背了你的初衷!

赶紧把GetHashCode()修正成忽略大小写的版本:

public override int GetHashCode() 
    => StringComparer.InvariantCultureIgnoreCase.GetHashCode(value);

最后验证一下

现在重新初始化NHibernate会话,应该就能正常加载PersonInfo的Emails集合了,每个元素都是EmailAddress对象,而且比较的时候会自动忽略大小写,再也不用手动记着加StringComparison了!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:38:07