Эти последние две недели были моим первым опытом с Castle ActiveRecord и с шаблоном ActiveRecord в целом. Я работаю над большой системой, которая часто ее использует, и я нахожу некоторые странные проблемы с транзакциями SQL (например, ниже), когда я работаю над этим. Я дам упрощенную версию той, которая меня полностью в тупик:Замок ActiveRecord - Всегда обновляйте детей, почему?
ИСТОРИЯ:
У меня есть класс ActiveRecord, давайте называть его пользователя.
Предположим, что у этого пользователя много объектов «Pet».
[ActiveRecord]
public class User: PersistentBase<User>
{
//...
[PrimaryKey]
public long Id
{
get;
set;
}
/// <summary>
/// Date and time the object was first persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime CreationDate
{
get;
set;
}
/// <summary>
/// Date and time the object was last persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime ModificationDate
{
get;
set;
}
/// <summary>
/// Property used for optimistic concurrency
/// </summary>
[Version]
public int LockCount { get; set; }
[HasMany(typeof(Pet), Cascade = ManyRelationCascadeEnum.SaveUpdate, Lazy = false, OrderBy = "Id")]
public IList<Pet> Pets { get; private set; }
//...
protected override bool BeforeSave(IDictionary state)
{
bool retval = base.BeforeSave(state);
DateTime now = DateTime.Now;
state["CreationDate"] = now;
state["ModificationDate"] = now;
return retval;
}
/// <summary>
/// Called when a dirty object is going to be updated in the db. Use this
/// hook to update ModificationDate.
/// </summary>
/// <param name="id"></param>
/// <param name="previousState"></param>
/// <param name="currentState"></param>
/// <param name="types"></param>
/// <returns></returns>
protected override bool OnFlushDirty(object id, IDictionary previousState, IDictionary currentState, IType[] types)
{
bool retval = base.OnFlushDirty(id, previousState, currentState, types);
currentState["ModificationDate"] = DateTime.Now;
return retval;
}
}
[ActiveRecord]
public class Pet : PersistentBase<Pet>
{
[PrimaryKey]
public long Id
{
get;
set;
}
/// <summary>
/// Date and time the object was first persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime CreationDate
{
get;
set;
}
/// <summary>
/// Date and time the object was last persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime ModificationDate
{
get;
set;
}
/// <summary>
/// Property used for optimistic concurrency
/// </summary>
[Version]
public int LockCount { get; set; }
//...
[BelongsTo("OwnerId")]
public User User { get; set; }
//...
protected override bool BeforeSave(IDictionary state)
{
bool retval = base.BeforeSave(state);
DateTime now = DateTime.Now;
state["CreationDate"] = now;
state["ModificationDate"] = now;
return retval;
}
/// <summary>
/// Called when a dirty object is going to be updated in the db. Use this
/// hook to update ModificationDate.
/// </summary>
/// <param name="id"></param>
/// <param name="previousState"></param>
/// <param name="currentState"></param>
/// <param name="types"></param>
/// <returns></returns>
protected override bool OnFlushDirty(object id, IDictionary previousState, IDictionary currentState, IType[] types)
{
bool retval = base.OnFlushDirty(id, previousState, currentState, types);
currentState["ModificationDate"] = DateTime.Now;
return retval;
}
}
Теперь у обоих из них есть автоматические поля Id (позаботились о SQL Server 2005).
ПРОБЛЕМА:
Если я иду вперед и добавить новое домашнее животное к пользователю, который уже имеет существующие домашние животное и сохранить пользователь, я вижу, если я бег SQL Profiler, что каждые один из домашних животных было ОБНОВЛЕНИЕ, вызванное на них ... но ни один не был изменен вообще.
Я бросил точки останова повсюду и обнаружил, что, когда я сохраняю пользователя, у каждого из них есть «OnFlushDirty» (опять же, хотя они никогда не менялись).
Внешний вид, который ищет (и иногда модифицирует) этих пользователей и домашних животных, вызывает серьезные проблемы с транзакциями, чего можно было бы избежать полностью, если вышеприведенный сценарий ТОЛЬКО добавит добавленное домашнее животное (а не ОБНОВЛЯЕТ домашних животных, которые не были изменены).
ВОПРОС:
не Делаю ли я что-то выше, что является большой нет-нет с точки зрения убедившись, что такая ситуация не происходит?
Благодарим за помощь, которую вы можете предоставить!
* EDIT 1: OnFlushDirty имеет нулевые previousState._values *
EDIT: OH! Я почти забыл самую странную часть всех!
Когда OnFlushDirty вызывается на этих домашних животных, в previousState и CurrentState существует ... они оба (будучи Dictionary) имеют внутренние переменные _values, которые должны иметь значения предыдущих и текущих состояний ...
... только currentStates имеет эту переменную, заполненную. Значение переменной «_values» предыдущегоState равно «null». Обратите внимание, что это касается всех домашних животных, которые существовали раньше. previousState всегда должно быть заполнено чем-то, не так ли?
* EDIT 2: После замены автомобилей Свойства ... *
я заменил список Авто недвижимости с традиционным частным членом с аксессорами собственности. Кажется, это не имело значения. Я установил NHProfiler в систему и обнаружил, что NHProfiler не смог подключиться к моему веб-приложению, если я запускал его через IIS (я использую IIS7/Win7 с Visual Studio 2008).
Я решил, что попробую вместо этого использовать Visual Studio «ASP.NET Development Server», чтобы увидеть, увидит ли тогда NHProfiler приложение.
Две вещей случились, когда я сделал это:
1) NHProfiler видел мое приложение и начал собирать данные 2) Множественные обновления, сделанные на детях ушло
Однако переключение обратно на IIS7/Win7, многочисленные обновления продолжают происходить.
Означает ли это, что это потенциально проблема конфигурации? Насколько мне известно, ничто в моей конфигурации не должно меняться, кроме URL-адреса, к которому я подключаюсь (http://localhost в IIS, http://localhost:(some_random_port) с ASP.NET Development Server) при использовании разных типов серверов. Так почему же две ситуации выше внезапно меняются?
О, интересно! Я постараюсь заменить это на более общий механизм ... может ли ICollection остановить проблему? Или, может быть, просто IEnumerable? – EdgarVerona
Проверьте эту ссылку: https://www.hibernate.org/hib_docs/nhibernate/html_single/#collections-persistent и обратите внимание на абзац, начинающийся с «Все типы коллекций, за исключением ISet и bag, имеют индексный столбец». быть, но я считаю, что это должно заставить вас начать. –
А, спасибо! Я глубоко ценю это! Сейчас я читаю документы, я дам вам шанс и дам вам знать, как это происходит! – EdgarVerona