Как отслеживать объекты, удаленные из коллекции ObservableCollection в сценариях CRUD? - PullRequest
5 голосов
/ 01 июня 2010

В нашем многоуровневом бизнес-приложении у нас есть ObservableCollections самопроверяющихся сущностей, которые возвращаются из сервисных вызовов.

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

Само-отслеживающиеся сущности, как можно предположить по их названию, сами отслеживают свое состояние. Когда создается новый STE, он имеет состояние «Добавлено», когда вы изменяете свойство, он устанавливает состояние «Изменено», он также может иметь состояние «Удалено», но это состояние не устанавливается, когда объект удаляется из ObservableCollection (очевидно) , Если вам нужно такое поведение, вам нужно написать его самостоятельно.

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

Что-то вроде:

protected IDictionary<int, IList> DeletedCollections = new Dictionary<int, IList>();

protected void SubscribeDeletionHandler<TEntity>(ObservableCollection<TEntity> collection)
{
    var deletedEntities = new List<TEntity>();
    DeletedCollections[collection.GetHashCode()] = deletedEntities;

    collection.CollectionChanged += (o, a) =>
        {
            if (a.OldItems != null)
            {
                deletedEntities.AddRange(a.OldItems.Cast<TEntity>());
            }
        };
}

Теперь, если пользователь решит сохранить свои изменения на сервере, я могу получить список удаленных элементов и отправить их вместе:

ObservableCollection<Customer> customers = MyServiceProxy.GetCustomers();

customers.RemoveAt(0);

MyServiceProxy.UpdateCustomers(customers);

На этом этапе метод UpdateCustomers проверит мою коллекцию теней, если какие-либо элементы были удалены, и отправит их на сервер.

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

Я придумал какое-то сложное решение, которое в данном случае в основном выполняет ручное управление памятью. Я сохраняю WeakReference до ObservableCollection и каждые несколько секунд проверяю, является ли ссылка неактивной, и в этом случае я удаляю коллекцию теней.

Но это кажется ужасным решением ... Я надеюсь, что коллективный гений StackOverflow сможет пролить свет на лучшее решение.

EDIT:

В конце концов я решил пойти с подклассами ObservableCollection. Код служебного прокси-сервера генерируется, поэтому его было довольно просто изменить, чтобы он возвращал мой производный тип.

Спасибо за помощь!

Ответы [ 3 ]

1 голос
/ 04 июня 2010

Если замена ObservableCollection возможна (например, если вы используете общую фабрику для всех экземпляров коллекций), то вы можете создать подкласс ObservableCollection и добавить метод Finalize, который очищает удаленные элементы, принадлежащие этой коллекции.

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

В противном случае ваше оригинальное решение звучит не так уж плохо. В java WeakReference может зарегистрировать обратный вызов, который вызывается при очистке ссылки. В .NET подобной функции нет, но использование опроса является близким приближением. Я не думаю, что этот подход настолько плох, и если он работает, то зачем его менять?

Кроме того, вас не беспокоит, что GetHashCode () возвращает одно и то же значение для разных коллекций? Использование слабой ссылки на коллекцию может быть более подходящим в качестве ключа, тогда вероятность столкновения отсутствует.

1 голос
/ 08 июня 2010

Я думаю, вы на правильном пути, я бы подумал о рефакторинге в этой ситуации. Мой опыт показывает, что в 99% случаев сборщик мусора делает управление памятью ошеломляющим - почти никакой реальной работы не требуется.

, но в 1% случаев требуется, чтобы кто-то осознал, что он должен поднять ставку и перейти на "старую школу", усилив управление кэшированием / памятью в этих областях. снимаю шляпу перед вами за понимание того, что вы находитесь в такой ситуации, и за попытку избежать трюков IDispose / WeakReference. Я думаю, что вы действительно поможете следующему парню, который работает в вашем коде.

Что касается решения, я думаю, вы хорошо разбираетесь в ситуации

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

удачи! расскажи как дела :) 1009 *

1 голос
/ 03 июня 2010

Вместо использования собственной логики «слабая ссылка + опрос Is is Dead, Is Alive», вы можете использовать HttpRuntime.Cache (доступно для всех типов проектов, а не только для веб-проектов).

Добавьте каждую коллекцию теней в Cache либо с щедрым таймаутом, либо с делегатом, который может проверить, жива ли исходная коллекция (или оба).

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

Кроме этого, вы смотрите на расширение ObservableCollection и использование этого нового класса вместо этого (который я представляю не малым изменением) или изменение / перенос UpdateCustomers метода для удаления формы коллекции теней DeletedCollections

Извините, я не могу думать ни о чем другом, но надеюсь, что это поможет.
BW

...