Как сопоставить базу данных, в которой первичные ключи состоят из 2 полей (одно установлено на вставке, одно удостоверение)? - PullRequest
0 голосов
/ 06 декабря 2010

В настоящее время я работаю над старым приложением ASP с базой данных SQL Server 2000, которое мы пытаемся перенести на новые технологии с использованием .NET и NHibernate .

В этой БД всетаблицы имеют составной идентификатор, подобный следующему:

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, гдеэлемент был создан
  • XXXIncId, который представляет собой поле IDENTITY, увеличенное при вставке новой строки

Суть SqlId заключается в том, что при репликации записи перемещаютсяиз базы данных в другую и может произойти дублирование XXXIncId.К сожалению, схема базы данных не меняется, так как многие приложения полагаются на нее (что, впрочем, и болезненно).

Это также означает, что всякий раз, когда существуют связи между таблицами, необходимо указывать оба поля, как в createdByIncId , createdBySqlId.

Я ищу лучший способ сопоставить эту структуру с NHibernate (Fluent илинет) но я заблокирован.Я рассмотрел следующие решения:

  • Использование Composite-ID с SqlId и IncId (наиболее естественное решение), но оно не работает, потому что IncId генерируется базой данныхи CompositeID не поддерживают «сгенерированный» атрибут
  • Полностью игнорируя эти поля и рассматривают «rowguid» как реальный идентификатор: это работает хорошо, пока я не пытаюсь поиграть сотношение между сущностями, которые также должны использовать «составной идентификатор» в качестве ссылки ...
  • Использование пользовательского составного типа пользователя (ICompositeUserType): но это нельзя использоватьв качестве идентификатора для сущности.

Мой вопрос довольно похож на вопрос 1615647 , но ответ меня не удовлетворяет.

Любая идея другоговести за собой?

1 Ответ

0 голосов
/ 15 декабря 2010

Мы опробовали 2 отведения:

  • пользовательских запросов на вставку SQL (<sql-insert>), которые не содержат поле IDENTITY, и запустили дополнительныйSQL-запрос после каждой вставки для заполнения свойства вручную.Это работало нормально в простых случаях использования (простой SELECT / INSERT), но не работало, как только вы ссылаетесь на другие сущности и коллекции других сущностей ...

  • использовать другое поле в качестве первичного ключа : каждая таблица также имеет столбец rowguid.Мы используем это как настоящий первичный ключ для NHibernate.Это хорошо работало в наших тестовых случаях каскадных вставок / обновлений.Наши составные идентификаторы - это обычные компоненты, которые помечены как , сгенерированные при вставке и , не включенные во время обновления , например:

    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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...