Nhibernate 如何映射主键由两个字段组成的数据库(一个字段设置为insert,一个字段标识)?

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

我目前正在使用SQL Server 2000数据库开发一个旧的ASP应用程序,我们正在尝试使用.NET和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();
    });
也就是说,每个表的主键由以下部分组成:

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();
    });
然后,对于实体之间的引用,我们指定用于建立关系的两列:

多对一:

一对多: