У меня есть случай, когда столбец «Дата обновления» сопоставлен с:
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, но они не сработали.Кто-нибудь еще сталкивался с этим?Есть ли элегантное решение?