Время жизни Datacontext в сценарии привязки WinForm - PullRequest
6 голосов
/ 19 декабря 2008

Это меня давно озадачило. Но я не эксперт. Это немного долго ...

У меня есть приложение WinForms с пользовательским интерфейсом в стиле Outlook. То есть на левой панели есть панель, которая позволяет вам выбрать «экран», который является элементом управления WinForms, скажем, экран клиента, а на правой панели появится список клиентов (т.е. контроль). Я называю это интерфейсом проводника. Двойной щелчок по записи вызовет немодальную запись о клиенте в дополнительном окне так же, как вы открываете электронное письмо в Outlook, мы называем это инспектором. Если дважды щелкнуть несколько записей, вы получите несколько инспекторов.

Все это делается с помощью привязки данных. Элемент управления BindingSource имеется в элементе управления списком клиентов, а другой - в инспекторе клиентов. Пользовательский элемент управления сообщает статический DataContext в своем событии загрузки и назначает результат простого запроса Linq-To-SQL свойству источника данных BindingControl. Если дважды щелкнуть список клиентов, событие ищет запись, преобразует ее в объект клиента Linq-To-SQL и передает ее в конструктор формы инспектора клиентов. Инспектор клиентов получает объект клиента и назначает ему свойство источника данных своего элемента управления BindingSource.

Поскольку элемент управления BindingSource поддерживает IBindingList, содержимое объекта клиента не изменяется до тех пор, пока не будет вызван EndEdit, в этом приложении при нажатии кнопки OK. Поскольку Linq to SQL реализует интерфейс INotifyPropertyChanged, список клиентов затем обновляется. Круто.

Однако проблема возникает, когда я хочу обновить содержимое списка клиентов, чтобы получать изменения, сделанные другими пользователями, что, как я хочу, происходит через регулярные промежутки времени, скажем, каждые 60 секунд. Если у меня есть таймер и я повторяю запрос к тому же текстовому тексту, никакие изменения не будут получены, потому что Linq to SQL не хочет отменять изменения, внесенные в данные, находящиеся под контролем текстового данных. Как ни странно, он выполняет запрос к БД, но отслеживание идентичности означает, что в список добавляются только новые объекты клиентов, возвращенные из БД. Если я создаю другой текстовый текст данных, то все открытые инспекторы клиентов больше не используют тот же текст данных, поэтому любые будущие изменения открытого инспектора клиентов не отражаются в списке клиентов.

В основном данные устарели, потому что я не использую шаблон единиц работы. Так что (если вы все еще со мной), вопросы.

1. Как, черт возьми, заставить эту модель работы работать в этой ситуации? В ASP.NET достаточно легко использовать текст данных с ограниченным объемом запроса, он недолговечный, но в WinForms?

2. Есть ли другие ORM, которые будут работать лучше в этом сценарии? NHibernate, EF, LLBLGEN и т. Д.

3. Как еще мне это сделать?

А также.

4. Если бы я мог заставить Linq to SQL работать таким образом, кто-нибудь реализовал IBindingList в частичных классах Linq to SQL, что позволило бы мне не использовать элементы управления IBindingSource. (Я не уверен, что должен заботиться об этом).

5. Если я смогу заставить Linq to SQL работать так, то есть ли способ использовать SQL-уведомления в SQL 2008, чтобы я мог получать уведомления об изменениях и запросах базового запроса, а не об опросе.

Спасибо!

P.S. Я знаю, что могу использовать

db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, customers)

, но это вызывает выполнение запроса к БД для каждой записи клиента в списке.

Ответы [ 5 ]

3 голосов
/ 21 мая 2009

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

У вас есть виджет, который представляет список объектов (СПИСОК). Когда вы щелкаете элемент в списке, появляется другой виджет, который позволяет пользователю редактировать объект. Когда пользователь завершил редактирование сущности, его изменения фиксируются в БД и также должны быть отражены в СПИСКЕ сущностей. Периодически система также должна извлекать изменения, внесенные другими пользователями в элементы списка, и обновлять список.

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

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

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

1) список привязан только к зафиксированным данным в БД. Это легко, когда инспектор сбрасывает локальные изменения обратно в базу данных и выполняет успешную фиксацию, предоставляя инспектору возможность сообщить списку об обновлении.

2) список привязан к зафиксированным данным + локальным не зафиксированным данным. Это немного сложнее, вам нужно представить методы в вашем списке, которые позволяют инспектору опережать данные, возвращаемые из БД, и перезаписывать их своими локальными грязными данными.

0 голосов
/ 17 мая 2009

Я пробовал подобное, вот мои два цента.

Я не думаю, что вы можете реализовать здесь единицу работы из-за того, как работает ваш пользовательский интерфейс. Как вы, возможно, уже знаете, LinqToSql DataContext разработан как легкий и недолговечный объект. Это естественно связывается с «единицей работы». В вашем случае фиксация изменений в БД - это одна единица, обновление изменений в БД - это другая единица. Но вы хотите, чтобы один экземпляр DataContext делал оба.

Кроме того, мне любопытно, что должен делать ваш пользовательский интерфейс, когда пользователь редактирует одну запись, в то время как другой пользователь просто фиксирует некоторые изменения в той же записи в БД. Как вы справляетесь с такими конфликтами параллелизма с точки зрения пользовательского интерфейса?

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

Ваша точка № 5 интересна. Мы делали что-то, что ничего не делало, кроме запросов к БД для сбора новейших обновлений, основанных на интервале или некоторых сигналах. Мы назвали это «издательским сервисом». Чтобы это работало, вам нужно иметь столбец отметки времени в вашей таблице БД.

Имея «службу публикации», вы можете получить набор дельты (обновления и новые записи), не используя DataContext в пользовательском управлении. Если вы «объедините» набор дельты с вашим локальным источником данных DataBinding, ваше представление сведений о клиенте должно обновиться. Теперь экземпляр DataContext в пользовательском элементе управления предназначен для обновления. Вы можете позволить пользователю решать, когда совершать. Или вы можете сделать это, когда пользователь покидает строку (во время проверки). Лично я бы сделал последнее, потому что мне не хочется, чтобы DataContext работал в течение непредсказуемого периода времени.

0 голосов
/ 10 марта 2009

Возможно, немного старый ... Но в отношении пунктов 4/5 обязательно ознакомьтесь с проектом Bindable LINQ на CodePlex. Там определенно есть хороший код, который точно решит вашу проблему.

http://www.codeplex.com/bindablelinq

0 голосов
/ 12 марта 2009

@ Андроник

После просмотра десятков ORM, я в настоящее время изучаю коммерческий ORM под названием Genome (http://www.genom -e.com / ).

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

@ Reddog

Я посмотрел на BindableLinq, и он мне действительно нравится. Но это Linq to Objects и, следовательно, не имеет перевода Linq to SQL, насколько я могу судить. (Если я не ошибаюсь).

Большое спасибо!

0 голосов
/ 20 февраля 2009

В настоящее время я пытаюсь реализовать идентичный сценарий в нашем приложении WinForms SmartClient.

Вы пришли к хорошему решению с этим?

В нашем приложении мы предъявляем те же требования к параллельному интерфейсу и обновляем данные из общего источника, однако вместо LinqToSql мы используем службы WCF. Я реализовал нашу собственную карту идентификации и решение для отслеживания изменений.

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

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

Наша проблема в том, что у нас открыто много окон одновременно, и пользователю легко вносить некоторые изменения, а не фиксировать их в бэкэнде. Тогда не понятно, почему они не могут перезагрузить основной список.

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

Вы придумали какие-нибудь лучшие решения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...