Смешивать WPF, LinqToSql и несколько потоков - плохая идея? - PullRequest
1 голос
/ 14 января 2009

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

У меня есть приложение WPF, отображающее иерархию. Дочерние элементы для каждого узла извлекаются с использованием запроса LinqToSql. Приложение отлично работает, когда есть одна нить.

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

<HierarchicalDataTemplate DataType="{x:Type viewmodels:NodeDM}" ItemsSource="{Binding Path=Children}">

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

<HierarchicalDataTemplate .. ItemsSource="{Binding Path=Children, IsAsync=True}">

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

System.Windows.Data Error: 16 : Cannot get 'Children' value (type 'ObservableCollection`1') from '' (type 'NodeDM'). BindingExpression:Path=Children; DataItem='NodeDM' (HashCode=29677729); target element is 'TreeViewItem' (Name=''); target property is 'ItemsSource' (type 'IEnumerable') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Specified cast is not valid.
   at System.Data.SqlClient.SqlBuffer.get_Int32()
   at System.Data.SqlClient.SqlBuffer.get_Value()
   at System.Data.SqlClient.SqlDataReader.GetValueInternal(Int32 i)
   <snipped around 20-30 lines>
   at System.Data.Linq.Table`1.GetEnumerator()
   at System.Data.Linq.Table`1.System.Collections.Generic.IEnumerable<TEntity>.GetEnumerator()
   at System.Linq.Lookup`2.CreateForJoin(IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.<JoinIterator>d__61`4.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at ICTemplates.Models.NodeDM.Load_Children()
   at ICTemplates.Models.NodeDM.get_Children()

Другие включают

System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

У меня деформированное дерево, в котором некоторые узлы не удалось загрузить. У меня есть одноэлементный экземпляр всемогущего класса LinqToSql DataContext, который общается с БД. Поэтому я попытался установить блокировку, чтобы несколько рабочих потоков не обращались к ней одновременно ... но не повезло.

partial class Node
{
  public IEnumerable<Segment> Children
  {
    lock (MyDatabaseDataContext.m_lockObject)
    {
      return // LINQ Query to join 2 tables and return a result
    }
  }

Отмена изменения IsAsync снова делает все хорошо. Почему свойство IsAsync портит LinqToSql? WPF Treeview достаточно, чтобы нормальные люди вырывали свои волосы.

1 Ответ

0 голосов
/ 14 января 2009

Кажется, ваша проблема связана с использованием того же объекта подключения для чтения. Когда у вас есть синхронный доступ к данным, обычно достаточно одного подключения, если вы не забыли открывать / закрывать между операциями чтения. Вы можете изменить свой код GetChildren для создания новых соединений (и команд / читателей данных и т. Д.) При каждом вызове, чтобы несколько потоков не наступали друг другу на пальцы. Также, если результаты кэшируются в памяти в некоторой структуре, попытайтесь синхронизировать доступ к этой структуре, используя блокировки. Вы не хотите, чтобы один поток пытался перечислить ваши элементы, в то время как другой пытается добавить новые.

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