Текущий столбец nHIbernate, сопоставленный с версией в базовом классе - сохранение дочернего элемента приводит к ошибке «объект ссылается на несохраненный временный экземпляр ...» в родительском элементе - PullRequest
0 голосов
/ 12 мая 2011

У меня есть случай, когда столбец «Дата обновления» сопоставлен с:

public abstract class AuditableEntityMapBase<T> : ClassMap<T>
{
    protected AuditableEntityMapBase()
    {
        ...
        OptimisticLock.Version();
        Version(x => (x as AuditableEntityBase).UpdateDT).Nullable();
        ...
    }
}

в базовом классе AuditableEntityMapBase, который наследуют объекты Parent (Person) и Child (PersonTelephone с Cascade.None for Person), как показано ниже::

public class PersonTelephoneMap : AuditableEntityMapBase<PersonTelephone>
{
    public PersonTelephoneMap()
    {
        Table("pers_PersonTelephone");

        Id(x => x.Id, "PersonTelephoneId");

        References(x => x.Person, "PersonId")
            .Cascade.None();
        ...
    }
}

и

public class PersonMap : AuditableEntityMapBase<Person>
{
    public PersonMap()
    {
        Table("pers_Person");

        Id(x => x.Id, "PersonId"); //.Unique().GeneratedBy.Native();

        ...

        HasMany(x => x.Phones)
            .KeyColumn("PersonId")
            .Inverse()
            .Cascade.All();

        ...
    }
}

Сохранение дочернего и сбрасывающего сеансов, как в следующем тесте, приводит к тому, что «объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом» в Parent:

/// <summary>
/// Tests nHibernate for concurrency (dirty read)
/// 1. Telephone1 and Telephone2 entities are loaded in separate sessions
/// 2. Telephone1 is updated - Telephone2 now has a dirty read
/// 3. Update Telephone2 and expect NHibernate.StaleObjectStateException error
/// </summary>
[Test]
[ExpectedException("NHibernate.StaleObjectStateException")] //Assert
public void CanVersionConcurrencyPersonTelephone()
{
    //Arrange
    const string telNo1 = "911";
    const string telNo2 = "999";            
    Person person2 = null;
    PersonTelephone personTelephone2 = null;

    var person = CreatePerson(); //Create a new person entity            
    var personManager = new PersonManager();           

    //Act
    //var person1 = personManager.Read(person.Id);
    var personTelephone1 = person.Phones[0];
    SessionContext.Current.AttachEntity(personTelephone1);
    SessionContext.Flush();

    using (SessionContext.Open())
    {
        person2 = personManager.Read(person.Id);
        personTelephone2 = person2.Phones[0];
        SessionContext.Flush();
    }

    System.Threading.Thread.Sleep(2000); //Arrange for a dirty read by user delay 

    using (SessionContext.Open())
    {
        personTelephone1.Number = telNo1;
        personManager.UpdateTelephone(personTelephone1); //simulate dirty read for personTelephone2
        SessionContext.Flush();
    }

    using (SessionContext.Open())
    {
        personTelephone2.Number = telNo2;
        personManager.UpdateTelephone(personTelephone2); //expect NHibernate.StaleObjectStateException
        SessionContext.Flush();
    }
}

Мне нецелесообразно увлажнять сущность Person и обновлять nHibernate, используя Cascade.SaveUpdate вместо Cascade.SaveUpdate при сопоставлении PersonTelephone следующим образом:

 References(x => x.Person, "PersonId")
                .Cascade.SaveUpdate();

Я такжепопытался использовать метод ReadOnly, который сначала сработал:

References(x => x.Person, "PersonId")
                    .Cascade.None.ReadOnly();

Однако это вызвало проблему со мной при вставке в таблицу PersonTelephone, поскольку PersonId является столбцом Not Null и не был введен во время вставки nHibernate, посколькутолько для чтения.

Пессимистическая блокировка не подходит моему пользователю.и с OptimisticLock.All () наблюдается снижение производительности.Я также попытался использовать .Cascade.None () для сопоставления сущностей Person.

Единственное, что сработало, - это наличие уникального поля Update для таблиц Person и PersonTelephone.Это решение пахнет для меня.Затем я попытался дать уникальные имена полям сущностей nHibernate, но они не сработали.Кто-нибудь еще сталкивался с этим?Есть ли элегантное решение?

1 Ответ

0 голосов
/ 12 мая 2011

Вы изменили "право собственности" на запись о Лице; PersonTelephones "владеют" своей ссылкой на Person. Тем не менее, каскадные отношения являются нисходящими; Персональные телефоны сохраняются, когда есть их Персона, но не наоборот.

Итак, у вас есть новый Person с новым PersonTelephone, и вы сохраняете PersonTelephone. Человек еще не существует в БД, и NH сказали не спасать Человека, когда телефон Персона сохранен, поэтому единственное, что он может сделать, - это пожаловаться.

Чтобы это исправить, сохраните Person, а не PersonTelephone. Это вставит или обновит Person, а затем перейдет вниз, чтобы вставить или обновить PersonTelephones, включая ваш новый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...