фиксировать изменения в свойствах объекта - PullRequest
4 голосов
/ 29 сентября 2010

В моем приложении несколько бизнес-объектов (C #, Winforms, WinXP).Когда пользователь выполняет какое-либо действие в пользовательском интерфейсе, каждый из этих объектов изменяется и обновляется различными частями приложения.После каждой модификации мне нужно сначала проверить, что изменилось, а затем записать эти изменения, внесенные в объект.Цель регистрации этого состоит в том, чтобы создать всестороннее отслеживание действий, происходящих в приложении.

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

  1. для максимально точного захвата изменений
  2. при минимальных затратах на производительность.

например, бизнес-объекта:

public class MainClass1
{
    public MainClass1()
    {
        detailCollection1 = new ClassDetailCollection1();
        detailCollection2 = new ClassDetailCollection2();
    }

    private Int64 id;
    public Int64 ID
    {
        get { return id; }
        set { id = value; }
    }

    private DateTime timeStamp;
    public DateTime TimeStamp
    {
        get { return timeStamp; }
        set { timeStamp = value; }
    }

    private string category = string.Empty;
    public string Category
    {
        get { return category; }
        set { category = value; }
    }

    private string action = string.Empty;
    public string Action
    {
        get { return action; }
        set { action = value; }
    }

    private ClassDetailCollection1 detailCollection1;
    public ClassDetailCollection1 DetailCollection1
    {
        get { return detailCollection1; }
    }

    private ClassDetailCollection2 detailCollection2;
    public ClassDetailCollection2 DetailCollection2
    {
        get { return detailCollection2; }
    }

    //more collections here
}

public class ClassDetailCollection1
{
    private List<DetailType1> detailType1Collection;
    public List<DetailType1> DetailType1Collection
    {
        get { return detailType1Collection; }
    }

    private List<DetailType2> detailType2Collection;
    public List<DetailType2> DetailType2Collection
    {
        get { return detailType2Collection; }
    }
}

public class ClassDetailCollection2
{
    private List<DetailType3> detailType3Collection;
    public List<DetailType3> DetailType3Collection
    {
        get { return detailType3Collection; }
    }

    private List<DetailType4> detailType4Collection;
    public List<DetailType4> DetailType4Collection
    {
        get { return detailType4Collection; }
    }
}

//more other Types like MainClass1 above...

Я могу предположить, что у меня будет доступ к старым значениям и новым значениям объекта.

В этом случае я могу придумать 2 способапопытаться сделать это, не сказав, что явно изменилось.

  1. использовать отражение и перебирать все свойства объекта и сравнивать их с соответствующими свойствами более старого объекта.Зарегистрируйте любые свойства, которые изменились.Этот подход кажется более гибким, так как мне не нужно было бы беспокоиться, если какие-либо новые свойства будут добавлены к любому из объектов.Но это также может показаться слишком тяжелым.
  2. Внесите изменения в установщик всех свойств всех объектов.Кроме того факта, что мне понадобится изменить много кода, это кажется более грубой силой.Это будет сложным и негибким в обслуживании, если кто-нибудь обновит какой-либо из типов объектов.Но таким образом, это также может быть преформой, так как мне не нужно будет проверять, что изменилось, и записывать, какие именно свойства были изменены.Добро пожаловать

Ответы [ 3 ]

3 голосов
/ 29 сентября 2010

Я разработал такую ​​систему несколько лет назад. Идея заключалась в том, чтобы отслеживать изменения в объекте и сохранять эти изменения в базе данных, например, контроль версий для объектов.

Наилучший подход называется Аспектно-ориентированное программирование или AOP. Вы вводите «совет» в сеттеры и геттеры (фактически, все методы выполнения, геттеры и сеттеры являются просто специальными методами), позволяя вам «перехватывать» действия, выполняемые над объектами. Изучите Spring.NET или PostSharp для решений .NET AOP.

2 голосов
/ 29 сентября 2010

Возможно, я не смогу дать вам хороший ответ, но я скажу вам, что в подавляющем большинстве случаев вариант 1 НЕ является хорошим ответом.Мы имеем дело с очень похожим отражающим «ходоком по графику» в нашем проекте;В то время это казалось хорошей идеей, но это кошмар по следующим причинам:

  • Вы знаете, что объект изменился, но без высокого уровня знаний в рефлексивном классе «обработки изменений»о работе объектов над ним, вы можете не знать, почему.Если эта информация важна для вас, вы должны передать ее обработчику изменений, чаще всего через поле или свойство объекта домена, требуя изменений в вашем домене и передавая домену знания о бизнес-логике.
  • Изменения могут затрагивать несколько объектов, но журналы изменений на каждом уровне могут быть нежелательны;например, клиент может не захотеть видеть изменения в счетчике непогашенных ссуд Заемщика в журнале при утверждении нового Ссуды, но они хотят видеть изменения из-за консолидации.Управление правилами ведения журналов в этих случаях требует, чтобы классы обработки изменений знали больше о структуре, чем об одном объекте, что может очень быстро сделать объект обработки изменений ОЧЕНЬ большим и ОЧЕНЬ хрупким.
  • Требования вашегоGraph Walker, вероятно, больше, чем вы знаете;если ваш объектный граф включает в себя обратные ссылки или перекрестные ссылки, ходок должен знать, где он был, и самый простой способ сделать это - сохранить список объектов, которые он обрабатывал, и сверять текущий объект с теми, с которыми он работал, перед его обработкой (сделать антибэк-трекинг операцией N ^ 2).Он также не должен учитывать изменения объектов в графе, которые не будут сохраняться при сохранении верхнего уровня (ссылки, которые не являются «каскадными»).NHibernate дает вам возможность подключиться к своему собственному обходчику графиков и соблюдать каскадные правила в ваших сопоставлениях, что помогает, но если вы используете DAL по собственному усмотрению или вы действительно хотите регистрировать изменения в объектах, которыеNHibernate не будет каскадироваться, вам придется все это настроить самостоятельно.
  • Часть логики в обработчике может внести изменение, которое требует обновления «родительского» объекта (обновлениерассчитанное поле, пожалуй).Теперь вам нужно вернуться назад и повторно оценить измененный объект, если изменение представляет интерес для другой части логики обработки изменений.
  • Если у вас есть логика, которая требует создания и сохранения нового объекта, выдолжен сделать одну из двух вещей;прикрепить новый объект к графу где-нибудь (где он может или не может быть подхвачен ходоком), или сохранить новый объект в своей собственной транзакции (если вы используете ORM, объект не может ссылаться на объект из другого объекта)график с параметром «каскад», который будет первым сохранять его).
  • Наконец, он очень хорошо отражает как при обходе графика, так и при поиске «обработчиков» для конкретного объекта, передавая сложное дерево в такоефреймворк - это гарантированный скачок скорости в вашем приложении.

Я думаю, вы избавите себя от множества головных болей, если пропустите отражающий шаблон «обработчик изменений» и включите создание журналов аудита илилюбую логику перед сохранением в «единице работы», которую вы выполняете на бизнес-уровне, с помощью набора «регистраторов аудита».Это позволяет логике, вносящей изменения, использовать шаблон выбора алгоритма, такой как «Command» или «Strategy», чтобы сообщить вашей структуре аудита, какие именно изменения происходят, поэтому он может выбрать регистратор, который будет выдавать необходимые сообщения регистрации.

0 голосов
/ 04 ноября 2012

Смотрите здесь, как adempiere сделал журнал изменений: http://wiki.adempiere.net/Change_Log

...