Поделиться через


Привязка данных

LINQ to SQL поддерживает привязку к общим элементам управления, таким как элементы управления сеткой. В частности, LINQ to SQL определяет основные шаблоны привязки к сетке данных и обработке привязки основных сведений, как в отношении отображения, так и обновления.

Базовый принцип

LINQ to SQL преобразует запросы LINQ в SQL для выполнения в базе данных. Результаты строго типизированы IEnumerable. Поскольку эти объекты являются обычными объектами среды CLR, для отображения результатов можно использовать обычную привязку данных объектов. С другой стороны, операции изменения (вставки, обновления и удаления) требуют дополнительных действий.

Операция

Неявная привязка к элементам управления Windows Forms осуществляется через реализацию IListSource. Универсальные Table<TEntity> источники данных (Table<T> в C# или Table(Of T) Visual Basic) и универсальные DataQuery были обновлены для реализации IListSource. Обработчики привязки данных пользовательского интерфейса (Windows Forms и Windows Presentation Foundation) проверяют, реализует ли источник данных IListSource. Поэтому написание прямой привязки запроса к источнику данных для элемента управления неявно вызывает генерацию коллекции LINQ to SQL, как показано на следующем примере:

DataGrid dataGrid1 = new DataGrid();
DataGrid dataGrid2 = new DataGrid();
DataGrid dataGrid3 = new DataGrid();

var custQuery =
    from cust in db.Customers
    select cust;
dataGrid1.DataSource = custQuery;
dataGrid2.DataSource = custQuery;
dataGrid2.DataMember = "Orders";

BindingSource bs = new BindingSource();
bs.DataSource = custQuery;
dataGrid3.DataSource = bs;
Dim dataGrid1 As New DataGrid()
Dim dataGrid2 As New DataGrid()
Dim dataGrid3 As New DataGrid()

Dim custQuery = _
    From cust In db.Customers _
    Select cust

dataGrid1.DataSource = custQuery
dataGrid2.DataSource = custQuery
dataGrid2.DataMember = "Orders"

Dim bs = _
    New BindingSource()
bs.DataSource = custQuery
dataGrid3.DataSource = bs

То же самое происходит с Windows Presentation Foundation:

ListView listView1 = new ListView();
var custQuery2 =
    from cust in db.Customers
    select cust;

ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)custQuery2;
Dim listView1 As New ListView()
Dim custQuery2 = _
From cust In db.Customers _
Select cust

Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2

Поколения коллекций реализуются универсальными Table<TEntity> и универсальными DataQuery в GetList.

Реализация IListSource

LINQ to SQL реализуется IListSource в двух расположениях:

  • Источник данных — это Table<TEntity>: LINQ to SQL просматривает таблицу, чтобы заполнить DataBindingList коллекцию, которая сохраняет ссылку на таблицу.

  • Источник данных — это IQueryable<T>. Существует два сценария:

    • Если LINQ to SQL обнаружит базовые Table<TEntity> данные из источника IQueryable<T>, источник позволяет редактирование, и ситуация такая же, как в первом пункте.

    • Если LINQ to SQL не удается найти базовый Table<TEntity> объект, источник не разрешает редактирование (например, groupby). LINQ to SQL просматривает запрос для заполнения универсального SortableBindingList, который представляет собой простой BindingList<T>, реализующий функцию сортировки сущностей T по заданному свойству.

Специализированные коллекции

Для многих функций, описанных ранее в этом документе, BindingList<T> было специализировано для некоторых различных классов. Эти классы являются универсальными SortableBindingList и универсальными DataBindingList. Оба объявляются как внутренние.

Универсальный список SortableBindingList

Этот класс наследует от BindingList<T>и является сортируемой версией BindingList<T>. Сортировка — это решение с использованием памяти, и она никогда не обращается к базе данных напрямую. BindingList<T> реализует IBindingList, но не поддерживает сортировку по умолчанию. Однако BindingList<T> реализует IBindingList с помощью виртуальных методов ядра. Эти методы можно легко переопределить. Универсальные SortableBindingList переопределяют SupportsSortingCore, SortPropertyCore, SortDirectionCore и ApplySortCore. ApplySortCore вызывается ApplySort и сортирует список элементов T для заданного свойства.

Исключение возникает, если свойство не принадлежит типу T.

Чтобы выполнить сортировку, LINQ to SQL создает универсальный SortableBindingList.PropertyComparer класс, наследующий от универсального IComparer.Compare и реализующий средство сравнения по умолчанию для заданного типа T, a PropertyDescriptorи направления. Этот класс динамически создает Comparer типа T, где T является PropertyType для PropertyDescriptor. Затем компаратор по умолчанию извлекается из статического обобщенного Comparer. Экземпляр по умолчанию получается с помощью отражения.

Generic SortableBindingList также является базовым классом для DataBindingList. Общий SortableBindingList предлагает два виртуальных метода для приостановки или возобновления отслеживания добавления и удаления элементов. Эти два метода можно использовать для базовых функций, таких как сортировка, но будут действительно реализованы высшими классами, такими как универсальные DataBindingList.

Универсальный список DataBindingList

Этот класс наследует от универсального SortableBindingLIst. Generic DataBindingList сохраняет ссылку на базовый универсальный Table, который применяется для первоначального заполнения коллекции с помощью универсального IQueryable. Универсальный DatabindingList добавляет отслеживание добавления и удаления элементов в коллекции путем переопределения InsertItem() и RemoveItem(). Она также реализует абстрактную функцию отслеживания приостановки/возобновления для условного отслеживания. Эта функция позволяет универсальному DataBindingList использовать все полиморфные возможности функции отслеживания родительских классов.

Привязка к EntitySets

Привязка к EntitySet является особым случаем, так как EntitySet уже является коллекцией, реализующей IBindingList. LINQ to SQL добавляет поддержку сортировки и отмены (ICancelAddNew). Класс EntitySet использует внутренний список для хранения сущностей. Этот список представляет собой низкоуровневую коллекцию на основе универсального массива, класса ItemList.

Добавление функции сортировки

Массивы предоставляют метод сортировки (Array.Sort()), который можно использовать с Comparer, когда T является типом данных. LINQ to SQL использует универсальный класс SortableBindingList.PropertyComparer, описанный ранее в этом разделе, чтобы получить этот Comparer для указания свойства и направления сортировки. Метод вызывающий эту функцию добавляется в универсальный ApplySortItemList.

На стороне EntitySet теперь необходимо объявить поддержку сортировки:

  • SupportsSorting возвращает true.

  • ApplySort вызывает entities.ApplySort(), а затем OnListChanged().

  • SortDirection и SortProperty свойства предоставляют текущее определение сортировки, которое хранится в локальных элементах.

При использовании System.Windows.Forms.BindingSource и привязке EntitySet<TEntity> к System.Windows.Forms.BindingSource.DataSource необходимо вызвать EntitySet<TEntity>.GetNewBindingList, чтобы обновить BindingSource.List.

Если вы используете System.Windows.Forms.BindingSource и задаете свойство BindingSource.DataMember и задаете BindingSource.DataSource классу с именем свойства BindingSource.DataMember, который предоставляет EntitySet<TEntity, вам не нужно вызывать EntitySet>TEntity<>. GetNewBindingList для обновления BindingSource.List, но вы теряете возможность сортировки.

Кэширование

Запросы LINQ to SQL реализуют GetList. Когда класс BindingSource Windows Forms соответствует этому интерфейсу, он вызывает GetList() три раза для одного подключения. Чтобы обойти эту ситуацию, LINQ to SQL реализует кэш для каждого экземпляра для хранения и всегда возвращает ту же созданную коллекцию.

Отмена

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

Помимо этой функции, коллекция также может реализовать ICancelAddNew. Эта функция позволяет элементам управления отменить или проверить, проверен ли новый измененный элемент.

ICancelAddNew реализован во всех коллекциях привязанных данных LINQ to SQL (generic SortableBindingList и generic EntitySet). В обоих реализациях код выполняется следующим образом:

  • Позволяет вставлять и удалять элементы из коллекции.

  • Не отслеживает изменения, пока пользовательский интерфейс не фиксирует выпуск.

  • Не отслеживает изменения до тех пор, пока выпуск отменен (CancelNew).

  • Разрешает отслеживание фиксации выпуска (EndNew).

  • Позволяет коллекции вести себя нормально, если новый элемент не исходит из AddNew.

Устранение неполадок

В этом разделе приводятся несколько элементов, которые помогут устранить неполадки приложений привязки данных LINQ to SQL.

  • Необходимо использовать свойства; использование только полей недостаточно. Для Windows Forms требуется это использование.

  • По умолчанию, image, varbinary и timestamp типы баз данных сопоставляются с массивом байтов. Так как ToString() в этом сценарии не поддерживается, эти объекты не могут отображаться.

  • Член класса, сопоставленный с первичным ключом, имеет сеттер, но LINQ to SQL не поддерживает изменение идентичности объекта. Таким образом, первичный или уникальный ключ, используемый в сопоставлении, не может быть обновлен в базе данных. Изменение в сетке вызывает исключение при вызове SubmitChanges.

  • Если сущность привязана к двум отдельным решеткам (например, одной главной и другой подробной), то Delete в главной решетке не передается на подробную решетку.

См. также