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


Привязка данных (LINQ to SQL)

Обновлен: November 2007

Технология 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, как показано в следующем примере.

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
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;

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

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

Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2
ListView listView1 = new ListView();
var custQuery2 =
    from cust in db.Customers
    select cust;

ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)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", дескриптора PropertyDescriptor и направления. Этот класс динамически создает класс Comparer для "T", где "T" является типом PropertyType дескриптора PropertyDescriptor. Затем из статического универсального класса Comparer извлекается компаратор по умолчанию. Экземпляр по умолчанию получается с помощью отражения.

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

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

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

Привязка к коллекциям "EntitySet"

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

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

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

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

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

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

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

Кэширование

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

Отмена

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

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

Интерфейс ICancelAddNew реализуется во всех коллекциях привязки данных LINQ to SQL (универсальном классе SortableBindingList и универсальном классе EntitySet). В обоих реализациях код выполняет перечисленные ниже задачи.

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

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

  • Не отслеживает изменений, если версия отменена (CancelNew).

  • Разрешает отслеживать фиксацию версий (EndNew).

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

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

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

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

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

  • Для члена класса, сопоставленного первичному ключу, имеется метод установки, однако LINQ to SQL не поддерживает изменение идентификации объекта. Поэтому первичный/уникальный ключ, используемый в сопоставлении, не может быть обновлен в базе данных. При вызове метода SubmitChanges изменение сетки вызывает исключение.

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

См. также

Другие ресурсы

Дополнительные сведения (LINQ to SQL)