4

Я пытался выяснить этот вопрос довольно долго. У меня есть хакерский способ заставить его работать.Свободное отображение составных клавиш Nhibernate

Я просто хочу знать, возможно ли это в переводе Fluent NHibernate.

Скажем, у меня есть две таблицы, например:

Table ComissionLevel 
{ 
    Year, 
    ComissionLevelID, 

    ... other properties .... 
} 
primary key (Year,ComissionLevelID) 

Table ClientCommission 
{ 
    Year, 
    ClientID, 
    CommissionLevelID_1, 
    CommissionLevelID_2, 

    ... other properties ... 
} 
primary key (Year,ClientID) 
foreign key CommissionLevel1 (Year,CommissionLevelID_1) 
foreign key CommissionLevel2 (Year,CommissionLevelID_2) 

В настоящее время мои отображения являются следующие:

public ComissionLevelMap() 
{ 
    Schema("XXXX"); 
    Table("ComissionLevel"); 
    LazyLoad(); 
    CompositeId() 
    .KeyProperty(x => x.Year, set => { 
     set.ColumnName("Year"); 
     set.Access.Property(); }) 
    .KeyProperty(x => x.CommissionLevelID, set => { 
     set.ColumnName("CommissionLevelID"); 
     set.Length(10); 
     set.Access.Property(); }); 

    HasMany<ClientCommission>(x => x.ClientCommissions) 
    .Access.Property() 
    .AsSet() 
    .Cascade.AllDeleteOrphan() 
    .LazyLoad() 
    .Inverse() 
    .Generic() 
    .KeyColumns.Add("Year", mapping => mapping.Name("Year") 
                 .SqlType("NUMBER") 
                 .Nullable()) 
    .KeyColumns.Add("CommissionLevelID_1", mapping => mapping.Name("CommissionLevelID_1") 
                 .SqlType("VARCHAR2") 
                 .Nullable() 
                 .Length(10)); 
    HasMany<ClientCommission>(x => x.ClientCommission2s) 
    .Access.Property() 
    .AsSet() 
    .Cascade.AllDeleteOrphan() 
    .LazyLoad() 
    .Inverse() 
    .Generic() 
    .KeyColumns.Add("Year", mapping => mapping.Name("Year") 
                 .SqlType("NUMBER") 
                 .Nullable()) 
    .KeyColumns.Add("CommissionLevelID_2", mapping => mapping.Name("CommissionLevelID_2") 
                 .SqlType("VARCHAR2") 
                 .Nullable() 
                 .Length(10)); 
} 

public ClientCommissionMap() 
{ 
    Schema("XXXXX"); 
    Table("ClientCommission"); 
    LazyLoad(); 
    CompositeId() 
    .KeyProperty(x => x.ClientID, set => { 
     set.ColumnName("ClientID"); 
     set.Length(10); 
     set.Access.Property(); }) 
    .KeyProperty(x => x.Year, set => { 
     set.ColumnName("Year"); 
     set.Access.Property(); }); 
    References(x => x.ComissionLevel1) 
    .Class<ComissionLevel>() 
    .Access.Property() 
    .Cascade.None() 
    .LazyLoad() 
    .Insert() 
    .Update() 
    .Columns("Year", "CommissionLevelID_1"); 
    References(x => x.ComissionLevel2) 
    .Class<ComissionLevel>() 
    .Access.Property() 
    .Cascade.None() 
    .LazyLoad() 
    .Insert() 
    .Update() 
    .Columns("Year", "CommissionLevelID_2"); 

} 

Моя проблема теперь, когда я создаю CommissionLevel и назначить ClientCommission для своей коллекции, если Я сохраняю их по вызову session.save (CommissionLevel), это сделает меня исключением.

<Index was out of range. Must be non-negative and less than the size of the collection. 
Parameter name: index>. 

Мой вопрос здесь:

  1. Неужели NHibernate автоматически сохраняет отношения? как:

    ClientCommission commission = new ClientCommission{Year = 2012, ClientID =SomeGuid}; 
        CommissionLevel newCommissionLevel = new CommissionLevel{Year = 2012, CommissionLevelID =NewCommissionLevelGuid}; 
    
        newCommissionLevel.ClientCommission1s.Add(commission); 
        newCommissionLevel.ClientCommission2s.Add(commission); 
    
        CommissionLevelRepo.Save(newCommissionLevel); 
    

    Когда я называю CommissionLevelRepo.Save (newCommissionLevel), должны NHibernate также обновит ClientCommission.ComissionLevel1 И ClientCommission.ComissionLevel2

или я должен сказать

ClientCommission.ComissionLevel1 = newCommissionLevel; 
ClientCommission.ComissionLevel2 = newCommissionLevel; 
  1. Для исключения, которое я получил, это потому, что NHibernate не генерирует правильный столбец, похоже, он будет генерировать ree Year columns. Если бы я вручную создал два свойства, называемые ComissionLevelID1 и CommissionLevelID2, отключите .Insert() и .Update() на ClientCommission, он сохранит его правильно.

Может ли кто-нибудь показать мне правильный способ сопоставить эти два класса?

Большое спасибо.

+0

просто мысли. если вы представляете всю эту сложность. u, вероятно, делают что-то неправильно. упростите отображение и дизайн. вы не сможете его поддерживать позже. – DarthVader

ответ

5

короткого ответа: вы не можете разделить столбцы для нескольких ссылок

длинного ответа: NHibernate обрабатывает каждый ссылочные независимо друг от друга, но делает исключить повторяющиеся столбцы в операторах вставки, поэтому ссылки пытаются получить доступ столбцов, которых больше нет. он делает это, потому что, если общий столбец отличается от ссылок к объектам в объектной модели, он не может решить, какой из них правильный.

Если вы можете изменить схему базы данных и сделать идентификаторы уникальными, тогда проигнорируйте весь год в идентификаторах и ссылках.

Update:

вы можете упростить некоторые из отображений

CompositeId() 
    .KeyProperty(x => x.Year, set => { 
     set.ColumnName("Year"); 
     set.Access.Property(); }) 
    .KeyProperty(x => x.CommissionLevelID, set => { 
     set.ColumnName("CommissionLevelID"); 
     set.Length(10); 
     set.Access.Property(); }); 

// to 
CompositeId() 
    .KeyProperty(x => x.Year) // columnname is equal propertyname by default 
    .KeyProperty(x => x.CommissionLevelID, set => set.Length(10).Access.Property()); // property is default access and can also be left out 


.SqlType("VARCHAR2").Length(10) 
// to 
.Length(10) or .SqlType("VARCHAR2") 
// because length is ignored when sqltype is specified 
+0

Большое спасибо. К сожалению, я не могу изменить db_schema. DBA не позволяет нам это делать. Могу ли я спросить, откуда вы прочитали эти знания об NHibernate? Есть документация где-то? – user1494907

+0

Большая часть этого - болезненный опыт с устаревшими dbs. Я обнаружил причины при поиске по Google, чтении источника NH, проб и ошибок. Каждый раз, когда вы сталкиваетесь с такой проблемой, вы должны идти на компромиссы. Либо отобразите его по-другому (например, игнорируйте первичные/внешние ключи в db, если части уникальны), отбросьте частные свойства в domainmodel, выполните nhibernate hooks, чтобы обойти обработку NHibernate по умолчанию. – Firo

0

Для составного ключа, посмотрите на Mapping Composite keys in Fluent NHibernate

Чтобы упростить отображение, вы можете изменить первичный ключ только один ключ и создать уникальный индекс для его представления, но это не лучшее решение.

Перед (композитный ключ):

CREATE TABLE XPTO (COD_XPTO1 INT NOT NULL IDENTITY, 
        COD_XPTO2 INT NOT NULL, 
        TXT_XPTO VARCHAR(10) NOT NULL) 
ALTER TABLE XPTO 
    ADD CONSTRAINT PK_XPTO (COD_XPTO1, COD_XPTO2) 

После (один ключ с уникальным индексом):

CREATE TABLE XPTO (COD_XPTO1 INT NOT NULL IDENTITY, 
        COD_XPTO2 INT NOT NULL, 
        TXT_XPTO VARCHAR(10) NOT NULL) 

ALTER TABLE XPTO 
    ADD CONSTRAINT PK_XPTO (COD_XPTO1) 

CREATE UNIQUE INDEX UK_XPTO ON XPTO (COD_XPTO1, COD_XPTO2) 
Смежные вопросы