0

我目前正在开发一个带有 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

也就是说,每个表的主键由:

  • XXXSqlId,它是创建项目的 SQL Server 实例的 ID
  • XXXIncId,这是一个IDENTITY在插入新行时递增的字段

关键SqlId在于,当复制发生时,记录会从一个数据库移动到另一个数据库,并且XXXIncId可能会发生重复。不幸的是,没有更改数据库模式,因为很多应用程序都依赖它(这确实很痛苦)。

这也意味着每当表之间存在关系时,都需要提供两个字段,如createdByIncId , createdBySqlId.

我正在寻找用 NHibernate(流利与否)映射此结构的最佳方法,但我被阻止了。我考虑了以下解决方案:

  • 使用带有 SqlId 和 IncId 的Composite-ID(最自然的解决方案)但它不起作用,因为 IncId 是由数据库生成的,并且 CompositeID 不支持“生成”属性
  • 完全忽略这些字段并将“rowguid”视为真实 ID:只要我不尝试处理实体之间的关系,这也很有效,它也应该使用“复合 ID”作为链接......
  • 使用自定义复合用户类型( ICompositeUserType) :但这不能用作实体的 ID。

我的问题与问题1615647非常相似,但答案对我来说并不令人满意。

有什么想法可以跟进吗?

4

1 回答 1

0

我们尝试了 2 条线索:

  • <sql-insert>不包含该字段的自定义插入 SQL 查询( ),IDENTITY并在每次插入后运行额外的 SQL 查询以手动填充属性。这在简单的用例(简单的 SELECT/INSERT)中效果很好,但在您引用其他实体和其他实体的集合时就不起作用了......

  • 使用另一个字段作为主键:每个表也有一个 rowguid 列。我们使用它作为 NHibernate 的真正主键。这在我们的级联插入/更新测试用例中运行良好。我们的复合 ID 只是常规组件,在插入时标记为生成,更新期间不包括在内,如下所示:

    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();
        });
    

然后,对于实体之间的引用,我们指定用于建立关系的 2 列:

多对一:

    References<LanguageEntity>(e => e.Language)
        .Columns("languageSqlId",
                 "languageIncId")
        .PropertyRef(l => l.Id)
        .Fetch.Join()
        .Cascade.None();

一对多:

    HasMany<InterfaceTranslationEntity>(e => e.Translations)
        .KeyColumns.Add("InterfaceSqlId",
                        "InterfaceIncId")
        .PropertyRef("Id") //name of the property in InterfaceTranslationEntity
        .Inverse();
于 2010-12-15T08:30:01.120 回答