Fluent NHibernate一对多映射报错:'Foreign Keys'集合名称无效
Fluent NHibernate映射异常排查:"Invalid collection name: 'Foreign Keys'"
问题重现
映射Asset和LogData类时,执行SchemaUpdate.Execute(false, true)抛出异常:
{"Invalid collection name: 'Foreign Keys'. (Parameter 'collectionName')"}
涉及的实体类和映射代码如下:
Asset实体类
public class Asset { public virtual int AssetID { get; set; } public virtual string Name { get; set; } = "New Asset"; public virtual double Value1 { get; set; } public virtual double Value2 { get; set; } public virtual double Value3 { get; set; } public virtual double Value4 { get; set; } public virtual double Value5 { get; set; } public virtual double Value6 { get; set; } public virtual double Value7 { get; set; } public virtual double Value8 { get; set; } [Range(0, 100)] public virtual double Value9 { get; set; } public virtual IEnumerable<LogData> Log { get; set; } = new List<LogData>(); }
LogData实体类
public class LogData { public virtual Asset Parent { get; set; } = new(); public virtual DateTime Timestamp { get; set; } public virtual double Value1 { get; set; } public virtual double Value2 { get; set; } public virtual double Value3 { get; set; } public override bool Equals(object? obj){...} public override int GetHashCode(){...} }
Asset映射类
public AssetMap() { Id(x => x.AssetID,"AssetID").GeneratedBy.Increment(); Map(x => x.Name).Not.Nullable().Default("\'New Asset\'"); Map(x => x.Value1).Not.Nullable(); Map(x => x.Value3).Not.Nullable(); Map(x => x.Value4).Not.Nullable(); Map(x => x.Value5).Not.Nullable(); Map(x => x.Value6).Not.Nullable(); Map(x => x.Value7).Not.Nullable(); Map(x => x.Value8).Not.Nullable(); Map(x => x.Value9).Not.Nullable(); HasMany(x => x.Log) .AsBag() .Cascade.AllDeleteOrphan() .KeyColumn("AssetID") .Not.LazyLoad(); }
LogData映射类
public LogDataMap() { CompositeId() .KeyReference(x => x.Parent, "AssetID") .KeyProperty(x => x.Timestamp); Map(x => x.Value1).Not.Nullable(); Map(x => x.Value2).Not.Nullable(); Map(x => x.Value3).Not.Nullable(); }
解决方案
1. 升级NHibernate及Fluent NHibernate版本
这个异常在旧版本NHibernate(比如4.x及更早)中偶发,尤其是和SQL Server驱动配合时。建议升级到NHibernate 5.x+的稳定版本,同时匹配对应版本的Fluent NHibernate,很多Schema生成相关的bug在新版本中已修复。
2. 调整复合主键映射写法
复合主键中使用KeyReference可能导致Schema工具识别外键集合时出错,尝试显式映射关联字段,同时保留复合主键:
public LogDataMap() { // 用AssetID作为复合主键的一部分,而非直接引用Parent CompositeId() .KeyProperty(x => x.Parent.AssetID, "AssetID") .KeyProperty(x => x.Timestamp); // 显式映射Parent关联,设置不插入/更新(因为主键已维护关联) References(x => x.Parent, "AssetID").Not.Insert().Not.Update(); Map(x => x.Value1).Not.Nullable(); Map(x => x.Value2).Not.Nullable(); Map(x => x.Value3).Not.Nullable(); }
注意:确保LogData的Equals和GetHashCode方法基于Parent.AssetID和Timestamp实现,保证实体唯一性判断正确。
3. 改用独立主键+唯一约束
如果业务允许,给LogData添加独立主键,将AssetID和Timestamp设为唯一约束,彻底避免复合主键带来的问题:
修改LogData实体类
public class LogData { public virtual int LogDataID { get; set; } // 新增独立主键 public virtual Asset Parent { get; set; } = new(); public virtual DateTime Timestamp { get; set; } public virtual double Value1 { get; set; } public virtual double Value2 { get; set; } public virtual double Value3 { get; set; } public override bool Equals(object? obj){...} public override int GetHashCode(){...} }
修改LogData映射类
public LogDataMap() { Id(x => x.LogDataID).GeneratedBy.Increment(); References(x => x.Parent, "AssetID").Not.Nullable(); Map(x => x.Timestamp).Not.Nullable(); // 添加唯一约束,保证一个Asset在同一时间只有一条LogData UniqueKey("UQ_Asset_Timestamp").Columns("AssetID", "Timestamp"); Map(x => x.Value1).Not.Nullable(); Map(x => x.Value2).Not.Nullable(); Map(x => x.Value3).Not.Nullable(); }
调整Asset映射类的HasMany配置
HasMany(x => x.Log) .AsBag() .Cascade.AllDeleteOrphan() .KeyColumn("AssetID") .Not.LazyLoad() .Inverse(); // 让LogData维护关联关系,避免冗余操作
4. 检查数据库驱动兼容性
确保使用的数据库驱动和NHibernate版本匹配,比如使用NHibernate.Driver.SqlClientDriver时,对应.NET版本的驱动包没有兼容性问题。
5. 直接使用SchemaExport初始化表结构
如果是首次初始化数据库,可以跳过SchemaValidator,直接用SchemaExport创建表:
new SchemaExport(configuration).Create(false, true);
创建完成后再用SchemaValidator验证结构即可。
内容的提问来源于stack exchange,提问作者GalaxyGuy
相关产品推荐
相关产品推荐

