1

Эти последние две недели были моим первым опытом с 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) при использовании разных типов серверов. Так почему же две ситуации выше внезапно меняются?

ответ

1

Активный участник замка IIRC полагается на NHib.

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

Я не проверял это, но IIRC, это ваша проблема.

+0

О, интересно! Я постараюсь заменить это на более общий механизм ... может ли ICollection остановить проблему? Или, может быть, просто IEnumerable? – EdgarVerona

+0

Проверьте эту ссылку: https://www.hibernate.org/hib_docs/nhibernate/html_single/#collections-persistent и обратите внимание на абзац, начинающийся с «Все типы коллекций, за исключением ISet и bag, имеют индексный столбец». быть, но я считаю, что это должно заставить вас начать. –

+0

А, спасибо! Я глубоко ценю это! Сейчас я читаю документы, я дам вам шанс и дам вам знать, как это происходит! – EdgarVerona

1

Это мертво просто. ActiveRecord не может справиться с C# -autoproperties в коллекциях (из-за типа интерфейса). Используйте поле подложки, а и инициализировать его с

private IList<Pet> pets = new List<Pet>(); 

-Markus

+0

О, я не знал этого! Это где-то в документации? Я не видел никаких упоминаний об этом, но это определенно хорошо знать. Я сделаю снимок, как только получу вернемся к нему в понедельник и дам вам знать! Знаете ли вы о каких-либо хороших ресурсах, где я могу узнать больше об этих «gotchas» в ActiveRecord? – EdgarVerona

+0

Там должно быть какие-то хорошие ресурсы где-то на этом ... Я просто но не найти его. Либо я не смотрю в нужном месте в документах Castle, либо им не хватает этой информации ... и я не могу найти хорошую внешнюю ссылку, которая подскажет мне такие вещи . = ( – EdgarVerona

+0

Да, это не так. Я заменил все коллекции autoproperties в программе с явными свойствами, и это не имело значения ... оно все еще поднимает событие OnFlushDirty для неизмененных детей, с previousState._value все еще null. – EdgarVerona

1

Случается, что в спящий режим необходимо использовать слияние(), чтобы сделать это спящий режим «нагрузки» на previuos данные обособленного объекта, в замке эквивалент - метод SaveCopy().

Смежные вопросы