Nhibernate 如何映射主键由两个字段组成的数据库(一个字段设置为insert,一个字段标识)?
我目前正在使用SQL Server 2000数据库开发一个旧的ASP应用程序,我们正在尝试使用.NET和NHibernate将其移植到新技术 在该数据库中,所有表都有一个复合ID,如下所示:Nhibernate 如何映射主键由两个字段组成的数据库(一个字段设置为insert,一个字段标识)?,nhibernate,fluent-nhibernate,legacy-database,Nhibernate,Fluent Nhibernate,Legacy Database,我目前正在使用SQL Server 2000数据库开发一个旧的ASP应用程序,我们正在尝试使用.NET和NHibernate将其移植到新技术 在该数据库中,所有表都有一个复合ID,如下所示: CREATE TABLE [Languages]( [languageIncId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, [languageSqlId] [smallint] NOT NULL, ... [crea
CREATE TABLE [Languages](
[languageIncId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[languageSqlId] [smallint] NOT NULL,
...
[createdByIncId] [int] NOT NULL,
[createdBySqlId] [smallint] NOT NULL,
...
[lastModifiedByIncId] [int] NULL,
[lastModifiedBySqlId] [smallint] NULL,
[rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL,
...
CONSTRAINT [PK_Languages] PRIMARY KEY CLUSTERED
(
[languageIncId] ASC,
[languageSqlId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
Component<CustomCompositeIdType>(e => e.Id,
p =>
{
p.Map(i => i.SqlId, "languageSqlId")
.Insert()
.Not.Update()
.Not.Nullable();
p.Map(i => i.IncId, "languageIncId")
.Not.Update()
.Not.Nullable()
.Generated.Insert();
});
也就是说,每个表的主键由以下部分组成:
XXXSqlId,它是创建该项的SQL Server实例的Id
XXXIncId,是插入新行时递增的标识字段
SqlId的要点是,当复制发生时,记录会从一个数据库移动到另一个数据库,并且可能会发生重复的XXXIncId。不幸的是,没有改变数据库模式,因为如此多的应用程序依赖它,这确实是痛苦的
这还意味着,每当表之间存在关系时,都需要像createdByIncId、createdBySqlId中那样提供这两个字段
我正在寻找用NHibernate流利与否映射此结构的最佳方法,但我被阻止了。我考虑过以下解决办法:
将复合ID与SqlId和IncId一起使用是最自然的解决方案,但它不起作用,因为IncId是由数据库生成的,并且复合ID不支持生成的属性
完全忽略这些字段并将ROUGUID视为真正的ID:只要我不尝试使用实体之间的关系,它就可以很好地工作,它也应该使用复合ID作为链接。
使用自定义复合用户类型ICompositeUserType:但不能将其用作实体的ID。
我的问题和我的问题很相似,但答案并不令我满意
有没有其他潜在客户的想法?我们尝试了两个潜在客户: 自定义插入不包含标识字段的SQL查询,并在每次插入后运行额外的SQL查询以手动填充属性。这在简单用例简单选择/插入中运行良好,但在引用其他实体和其他实体的集合时不起作用 使用另一个字段作为主键:每个表也有一个rowguid列。我们使用它作为NHibernate的真正主键。这在级联插入/更新的测试用例中运行良好。我们的复合ID只是常规组件,标记为在插入时生成,在更新过程中不包含,如下所示:
CREATE TABLE [Languages](
[languageIncId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[languageSqlId] [smallint] NOT NULL,
...
[createdByIncId] [int] NOT NULL,
[createdBySqlId] [smallint] NOT NULL,
...
[lastModifiedByIncId] [int] NULL,
[lastModifiedBySqlId] [smallint] NULL,
[rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL,
...
CONSTRAINT [PK_Languages] PRIMARY KEY CLUSTERED
(
[languageIncId] ASC,
[languageSqlId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
Component<CustomCompositeIdType>(e => e.Id,
p =>
{
p.Map(i => i.SqlId, "languageSqlId")
.Insert()
.Not.Update()
.Not.Nullable();
p.Map(i => i.IncId, "languageIncId")
.Not.Update()
.Not.Nullable()
.Generated.Insert();
});
然后,对于实体之间的引用,我们指定用于建立关系的两列:
多对一:
一对多: