2010-12-06 2 views
0

В настоящее время я работаю над старым ASP-приложением с базой данных SQL Server 2000, которую мы пытаемся подключить к более новым технологиям с использованием .NET и NHibernate.Как создать базу данных, в которой первичные ключи состоят из 2 полей (один набор для вставки, один идентификатор)?

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

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

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

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

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

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

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

Любая идея другого привести к следующему?

ответ

0

Мы постарались 2 провода:

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

  • другое поле в качестве первичного ключа : каждая таблица также имеет столбец rowguid.Мы используем его как первичный ключ real для 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();